web-dev-qa-db-ja.com

Makefileでシェルコマンドを使用する方法

私はlsの結果を他のコマンド(echo、rsyncなど)で使用しようとしています:

all:
    <Building, creating some .tgz files - removed for clarity>
    FILES = $(Shell ls)
    echo $(FILES)

しかし、私は得る:

make
FILES = Makefile file1.tgz file2.tgz file3.tgz
make: FILES: No such file or directory
make: *** [all] Error 1

echo $$FILESecho ${FILES}およびecho $(FILES)を試してみましたが、運はありません。

84
Adam Matan

と:

FILES = $(Shell ls)

allの下にインデントされているのは、ビルドコマンドです。したがって、これは$(Shell ls)を展開し、コマンドFILES ...を実行しようとします。

FILESmake変数であると想定される場合、これらの変数はレシピ部分の外側に割り当てる必要があります。例:

FILES = $(Shell ls)
all:
        echo $(FILES)

もちろん、それはFILESが「output from ls」に設定されることを意味しますbeforeを作成するコマンドのいずれかを実行する.tgzファイル。 ( Kaz notes 変数は毎回再展開されるため、最終的には.tgzファイルが含まれます。一部のmakeバリアントには、これを回避するためにFILES := ...があります。 。1

FILESがシェル変数であることになっている場合、それを設定できますが、スペースなしで引用符で囲まれたシェルで行う必要があります。

all:
        FILES="$(Shell ls)"

ただし、各行は個別のシェルによって実行されるため、この変数は次の行まで存続しないため、すぐに使用する必要があります。

        FILES="$(Shell ls)"; echo $$FILES

シェルは最初に*(およびその他のシェルグロブ式)を展開するため、これは少しばかげているので、次のことができます。

        echo *

シェルコマンドとして。

最後に、一般的なルールとして(この例には実際には適用されません):as esperanto notes in notes、lsからの出力の使用は完全に信頼できません(一部の詳細はファイル名に依存し、時にはlsのバージョンでさえ、いくつかのバージョンのlsでさえ、場合によっては出力をサニタイズしようとします)。したがって、 l0b および idelic のように、GNU makeを使用している場合は、$(wildcard)および$(subst ...)を使用してmake自体の内部ですべてを実行します(「ファイル名の奇妙な文字」の問題を回避します)。 (メイクファイルのレシピ部分を含むshスクリプトでは、find ... -print0 | xargs -0を使用して、空白、改行、制御文字などをつまずかないようにする方法があります。)


1GNU 2012年にPOSIX makeが::=割り当てを追加したことをさらに文書化してください 。このためのPOSIX文書へのクイックリファレンスリンクは見つかりませんでした。また、GNU makeが今日行うのはどのmakeバリアントが::=割り当てをサポートするかを知っています:=と同じ意味、つまり、拡張を使用して今すぐ割り当てを行います。

VAR := $(Shell command args...)は、いくつかのmakeバリアント(_最新のGNUおよびBSDバリアントを含む)でVAR != command args...と綴ることもできることに注意してください。これらの他のバリアントには$(Shell)がないため、VAR != command args...を使用すると、より短いおよびより多くのバリアントで機能するという点で優れています。

125
torek

また、torekの答えに加えて、際立っていることの1つは、遅延評価されたマクロ割り当てを使用しているということです。

GNU Makeを使用している場合は、:=の代わりに=割り当てを使用します。この割り当てにより、右側がすぐに展開され、左側の変数に格納されます。

FILES := $(Shell ...)  # expand now; FILES is now the result of $(Shell ...)

FILES = $(Shell ...)   # expand later: FILES holds the syntax $(Shell ...)

=割り当てを使用する場合、$(FILES)が出現するたびに$(Shell ...)構文が展開され、シェルコマンドが呼び出されます。これにより、makeジョブの実行が遅くなるか、驚くべき結果になります。

45
Kaz