148

すべてのコマンドが独自のシェルで実行されることを考えると、makefileで複数行のbashコマンドを実行するための最良の方法は何ですか?たとえば、次のようになります。

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

5 に答える 5

168

行の継続には円記号を使用できます。ただし、シェルは1行に連結されたコマンド全体を受け取るため、一部の行をセミコロンで終了する必要があることに注意してください。

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

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

foo:
    gcc `find`

または、よりシェルの従来のアプローチを使用します(ただし、エスケープ$(command)に注意してください)。$

foo:
    gcc $$(find)
于 2012-04-12T10:13:15.070 に答える
113

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

makefile内にシェルスクリプトを作成するためのヒント:

  1. $で置き換えることにより、スクリプトの使用を回避します$$
  2. ;コマンド間に挿入して、スクリプトを1行として機能するように変換します
  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 ;\
    }
于 2015-03-16T19:48:29.957 に答える
10

ONESHELLディレクティブを使用すると、同じシェル呼び出しで実行される複数の行レシピを作成できます。

all: foo

SOURCE_FILES = $(shell find . -name '*.c')

.ONESHELL:
foo: ${SOURCE_FILES}
    FILES=()
    for F in $^; do
        FILES+=($${F})
    done
    gcc "$${FILES[@]}" -o $@

ただし、欠点があります。特殊なプレフィックス文字('@'、'-'、および'+')の解釈が異なります。

https://www.gnu.org/software/make/manual/html_node/One-Shell.html

于 2020-07-09T16:39:34.377 に答える
3

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

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

foo: $(wildcard *.h) $(wildcard *.c)
于 2012-05-07T15:30:27.057 に答える
1

コマンドを呼び出すだけの何が問題になっていますか?

foo:
       echo line1
       echo line2
       ....

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

編集:あなたの例は次のような1行のスクリプトに書き直すことができます:

gcc $(for i in `find`; do echo $i; done)
于 2012-04-12T09:57:10.117 に答える