
この命令に関する本を読んでいますが、make
その中に次の段落があります。
前提条件に関連する規則がある場合は、まずその規則を更新してみてください。次に、ターゲットファイルを考えます。前提条件がターゲットよりも最新の場合は、コマンドを実行してターゲットを再生成します。各コマンドラインはシェルに渡され、独自のサブシェルで実行されます。
そこで使用されるサブシェルの概念と、そのようなサブシェルを使用する理由を説明できますか?
答え1
make(1)
シェルコマンド自体を実行する方法がわかりません。この方法で行うこともできますが、Unixのアプローチは懸念をすばやく分離することです。つまり、make(1)
何をすべきかを決定するために依存関係グラフを作成する方法を知り、sh(1)
コマンドを実行する方法を知る必要があります。
作成者が言うべき点は、ファイルシステムを介している場合を除いて、後者のコマンドラインが前のコマンドラインに依存するようにコマンドラインを作成できないことです。たとえば、次は機能しません。
sometarget: some.x list.y of-dependencies.z
foo=`run-some-command-here`
run-some-other-command $$foo
これが2行のシェルスクリプトである場合、最初のコマンドの出力は2番目のコマンドの引数として渡されます。ただし、各コマンドは別々のサブシェルで実行されるため、最初のサブシェルが$foo
存在すると変数の値が失われるため、最初のサブシェルに渡すことはありません。
前述のように、この問題を解決する1つの方法はファイルシステムを使用することです。
TMPDIR=/tmp
TMPFILE=$(TMPDIR)/example.tmp
sometarget: some.x list.y of-dependencies.z
run-some-command-here > $(TMPFILE)
run-some-other-command `cat $(TMPFILE)`
2番目のコマンドが値をロードできるように、最初のコマンドの出力を永続的な場所に保存します。
時々初心者を混乱させるもう1つのことmake(1)
は、シェルスクリプトで読みやすくするために、通常は複数行に分割される構成を1行に書き込む必要があることです。または、Makefile
.loopにある場合、これの良い例は機能しません。 :
someutilitytarget:
for f in *.c
do
munch-on $f
done
すべてを1行に入れるには、セミコロンを使用する必要があります。
someutilitytarget:
for f in *.c ; do munch-on $f ; done
私自身の場合は、これを実行して、コマンドラインが約80文字を超えるたびに読み取れるように外部シェルスクリプトに移動します。
答え2
Make自体はシェルではないため、シェルで実行する必要があります。 make自体が(おそらく)シェルで実行されるので、この本ではこれを「サブシェル」と呼びます。本で実際に渡すことは、各コマンドに独自のシェルがあるため、1行から変数をエクスポートし、次の行(または別の後続行)で使用したい場合は機能しません(使用するシェルexport
は別のシェルで実行される次の行で終わります)します。
答え3
古い質問ですが、シェルでコマンドを実行して出力を取得することもできます。
http://electric-cloud.com/blog/2009/03/makefile-performance-shell/
OUTPUT = $(shell pwd)
some-target:
@echo $(OUTPUT)
答え4
つまり、ルールの各コマンドラインは、独自のシェルプロセスで呼び出されます。その理由は、makeが1つのコマンドラインを実行してから次のコマンドラインを呼び出す前にそれを確認しようとするためです。
コマンドを呼び出す別の方法を考えることができますが、これが方法です。作るその当時デザインされたものです。
確かに作るただできるフォーク()/exec()コマンドを使用しますが、シェルサブプロセスを使用すると、ユーザーはシェル機能を使用することもできます。