この簡単なレシピはなぜ効果がないのですか?
.PHONY: test
test:
foo := $(shell ls | grep makefile) ;\
echo $(foo)
明らかにする
$> make test
makefile:65: warning: undefined variable 'foo'
foo := makefile ;\
echo
/bin/sh: 1: foo: not found
それで、私が知っているのは、変数にfoo
値が設定されているのにmakefile
使用できないということですか?しかし、同じシェルで実行される単一行コマンドですか?
しかし、これはうまくいきます
@$(eval export foo := $(shell ls | grep makefile)) \
echo $(foo)
echo
もしそうなら、私たちが試したときに割り当てがまだ評価されていないため、最初の例の変数にアクセスできないようです。
もっと詳しく見ると、どうすればこれを行うことができますか?
.PHONY: test
test:
@$(eval export files = $(shell ls))
for f in $(files) ; do \
t = $(ls | grep $$f) ; \
echo $$t;\
done
答え1
私はあなたのループを見ました...引用は次のとおりです。
.PHONY: test
test:
@$(eval export files = $(shell ls))
for f in $(files) ; do \
t = $(ls | grep $$f) ; \
echo $$t;\
done
それでは... $(eval ... )
makeでコマンドを実行してみてください。
$(shell ls)
ls
シェルでコマンドを実行し、出力を置き換えます。
したがって、実行されるコマンドは$(eval ... )
次のとおりですexport files = file file2 makefile source.c
。このコマンドは、filesという名前のmake変数を生成し、それをsubmakeにエクスポートします。したがって、エクスポートが必要ない場合があります。
全体を$(eval ... )
置き換えて使用でき、ルールの外に配置files = $(wildcard *)
できます。:=
このfor
ループ(4行)はシェルで実行されます。最初にすることは、make変数と関数を置き換えることです。奇妙な点は$(ls | grep $$f)
。 ls は make 関数ではないため、未定義の変数を拡張しようとします。これは空の文字列です。これがシェル$(...)
演算子の場合は、$を2倍にする必要があります。 evalに基づいて.Extended $$
に拡張されます。$
$(files)
これは次のとおりです(前の例を使用した場合)。
for f in file file2 makefile source.c ; do
t =
echo $t;
done
一見すると、これは4つの空白行をエコーしているように見えるかもしれませんが、そうではありません。このコマンドはt =
実際にプログラムを実行し、t
等号を引数として渡します。 t
おそらく存在しないでしょう。したがって、tが有効なプログラムではないことを示す4つのエラーが発生します。各エラーの後には空行が続きます(tが他の場所で定義されていない場合)。
あなたが望むものに近いものは次のとおりです。
files := $(wildcard *)
.PHONY: test
test:
for f in $(files) ; do \
t=$$(ls | grep $$f) ; \
echo $$t ; \
done
すると、以下が出力されます。
file file2
file2
makefile
source.c
最初の行には名前に「file」が含まれているため、2つのファイルがリストされます。これが欲しいものではない場合は、次の点を検討してください。
files := $(wildcard *)
.PHONY: test
test:
for f in $(files) ; do \
echo $$f ; \
done
または(GNU固有の場合もあります):
files := $(wildcard *)
.PHONY: test
test:
$(foreach f, $(files), echo $f ; )
答え2
make targetレシピ内では、コマンドはレシピの外側のロジックとは異なる方法で処理されます(シェル生成)。
レシピの外に変数を移動できます。
.PHONY: test
foo := $(shell ls | grep makefile)
test:
echo $(foo)
または丁寧にこの問題、評価の使用:
.PHONY: test
test:
$(eval foo=$(shell ls | grep makefile))
echo $(foo)
どちらも以下を出力します。
echo makefile
makefile