web-dev-qa-db-ja.com

makefileの複数行のbashコマンド

数行のbashコマンドを使用してプロジェクトをコンパイルする非常に快適な方法があります。しかし、今はメイクファイルでコンパイルする必要があります。すべてのコマンドが独自のシェルで実行されることを考えると、私の質問はメイクファイルで複数行のbashコマンドを相互に依存して実行する最良の方法は何ですか?たとえば、このように:

for i in `find`
do
    all="$all $i"
done
gcc $all

また、誰かが単一行コマンドbash -c 'a=3; echo $a > file'でさえターミナルで正しく動作するが、メイクファイルの場合は空のファイルを作成する理由を説明できますか?

92
Jofsey

行の継続にはバックスラッシュを使用できます。ただし、シェルはコマンド全体を1行に連結して受信するため、いくつかの行をセミコロンで終了する必要があることに注意してください。

foo:
    for i in `find`;     \
    do                   \
        all="$$all $$i"; \
    done;                \
    gcc $$all

ただし、find呼び出しによって返されるリスト全体を取得してgccに渡すだけの場合、実際には必ずしも複数行のコマンドは必要ありません。

foo:
    gcc `find`

または、よりシェル型の$(command)アプローチを使用します(ただし、$はエスケープします):

foo:
    gcc $$(find)
108

質問に示されているように、すべてのサブコマンドは独自のシェルで実行されます。これにより、重要なシェルスクリプトの作成が少し面倒になります-しかし可能です!解決策は、スクリプトをmakeが考慮するものに統合することです単一のサブコマンド(単一行)。

メイクファイル内でシェルスクリプトを作成するためのヒント:

  1. $に置き換えることにより、スクリプトの$$の使用を回避します
  2. コマンド間に;を挿入して、スクリプトを単一行として機能するように変換します
  3. 複数行でスクリプトを作成する場合は、\を使用して行末をエスケープします
  4. オプションでset -eで始まり、サブコマンドの失敗時に中止するmakeのプロビジョニングに一致します
  5. これは完全にオプションですが、スクリプトを()または{}で囲んで、複数行のシーケンスの凝集性を強調することができます。これは典型的なmakefileコマンドシーケンスではありません。

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 ;\
    }
70
nobar

もちろん、Makefileを記述する適切な方法は、どのターゲットがどのソースに依存するかを実際に文書化することです。些細なケースでは、提案されたソリューションはfooをそれ自身に依存させますが、もちろんmakeは十分に賢く、循環依存関係を削除します。ただし、一時ファイルをディレクトリに追加すると、「魔法のように」依存関係チェーンの一部になります。おそらくスクリプトを使用して、依存関係の明示的なリストを一度だけ作成することをお勧めします。

GNU makeはgccを実行して.cおよび.hファイルのセットから実行可能ファイルを生成する方法を知っているため、実際に必要なのは

foo: $(wildcard *.h) $(wildcard *.c)
2
tripleee

コマンドを呼び出すだけで何が問題になりますか?

foo:
       echo line1
       echo line2
       ....

2番目の質問では、代わりに$、つまり$$を使用して、bash -c '... echo $$a ...'をエスケープする必要があります。

編集:あなたの例は、このような単一行のスクリプトに書き換えることができます:

gcc $(for i in `find`; do echo $i; done)
1
JesperE