web-dev-qa-db-ja.com

Makefileシェルを使用して変数を作成します

MakeのShellコマンドを使用していくつかの変数を設定していますが、出力時に、それらが期待する値に設定されていることを示しています。ただし、それらをmakeレシピに渡すと、すべて空になります。 makeが結果に対して奇妙な解析を行っているのではないかと思います。例えば:

MyTarget: $(MySources)
    LINE='$(Shell cat $< | grep GIMME_THE_LINE_I_WANT)'
    CH9=$(Shell echo $(LINE) | cut -b9)
    echo $(CH9) # doesn't print anything

Shell=sh -XVを設定してジェネレーターコマンドを手動でチェックしました。同じコマンドを実行すると、正しい値が得られ、bashが変数を「ゼロ化」しているように見えます。何が問題なのか分かりますか?

8
LambdaBeta

ここで起こっていることがいくつかあります。 1つ目は、次の場合です。

_MyTarget: $(MySources)
    LINE='$(Shell cat $< | grep GIMME_THE_LINE_I_WANT)'
_

LINE変数ではなく、makeというシェル変数を設定しています。ターゲットのビルド手順はすべてシェルコマンドです。したがって、最初の行の後、シェル変数_$LINE_には_GIMME_THE_LINE_I_WANT_が含まれます。しかしながら...

...各lineターゲットのビルド手順では、個別のシェルプロセスで実行されます。だからあなたが持っているなら:

_mytarget:
    MYVAR=foo
    echo $$MYVAR
_

2番目のコマンドのコンテキストでは_$MYVAR_が設定されていないため、出力は表示されません。また、ここで_$$_を使用していることに注意してください。そうしないと、_$_がMakeによって解釈されます(つまり、_$MYVAR_を書き込むと、実際にはmake式_$M_の後にテキストが続きます) YVAR)。これは、次のように、行を単一のシェルスクリプトに論理的に結合することで解決できます。

_mytarget:
    MYVAR=foo; \
    echo $$MYVAR
_

_\_は、単一の論理行を複数の物理行に拡張するMakefile構文です。もちろん、_;_は、1行に複数のコマンドを組み合わせるための単純なシェル構文です。

これらすべてを念頭に置いて、ターゲットを次のように書き直すことができます。

_MyTarget: $(MySources)
    LINE=$$(cat $< | grep GIMME_THE_LINE_I_WANT); \
    CH9=$$(echo $$LINE | cut -b9); \
    echo $$CH9
_

すでにシェルスクリプトを実行しているので、Makeの$(Shell ...)構造を使用しておらず、すべての_$_文字をエスケープしていることに注意してください。 MakeではなくShellが変数の展開を処理していることを確認します。

さらに少し進んで、そのスクリプトでcatを使用する必要はありません。あなたは単に書くことができます:

_MyTarget: $(MySources)
    LINE=$$(grep GIMME_THE_LINE_I_WANT $<); \
    CH9=$$(echo $$LINE | cut -b9); \
    echo $$CH9
_

または:

_MyTarget: $(MySources)
    CH9=$$(grep GIMME_THE_LINE_I_WANT $< | cut -b9); \
    echo $$CH9
_

(注:このソリューションに密接に関係しているわけではありませんが、$(Shell ...)の各呼び出しも別々のプロセスで実行されるため、ある変数セットが別のプロセスで使用できないことに注意してください。)

18
larsks

Makeは、すべてのコマンドを個別のシェルで実行します。したがって、値は引き継がれません。

疑わしい場合は、-dオプションを使用していつでもデバッグできます。また、サイトノートのデバッグオプションは、ルールが意図したとおりに実行されなかった理由を理解しようとするときに非常に役立ちます。

~> cat Makefile
MyTarget:
        LINE="somevalue"
        echo ${LINE}
~>
~>
~> make -d MyTarget | tail -10
LINE="somevalue"
Putting child 0x2004fbb0 (MyTarget) PID 4052 on the chain.
Live child 0x2004fbb0 (MyTarget) PID 4052
Reaping winning child 0x2004fbb0 PID 4052
echo
Live child 0x2004fbb0 (MyTarget) PID 4192

Reaping winning child 0x2004fbb0 PID 4192
Removing child 0x2004fbb0 PID 4192 from chain.
Successfully remade target file 'MyTarget'.
~>

上記の解決策が機能しないことを否定し、コメントした人々のために明確にするだけです。まず、怠惰をお詫びします。はっきりしているべきだったのかもしれません。もう一度やり直します。

「make-d」はOPの問題の解決策ではありません。

私はOPに、デバッグオプションを使用して、メイクファイルの使用中に発生するさまざまな問題を解決する方法を示しました(これは、OPの問題を解決するだけではなく、わずかに正接します)。

上記のデバッグは、最初のコマンドがPID = 4052のシェルで実行され、2番目のコマンドがPID = 4192(その変数の値を持たない)の別のシェルで実行されたことを示しています。また、1ドル($ {LINE})の変数を使用すると、空白が表示されることも示されています(makefileはそれをシェル変数として解釈しないため)。

繰り返しますが、明確にするために、「make-d」は解決策ではありません。コマンドをコンマで区切って1行にまとめ、2ドルを使用します。行が長い場合は、新しい行をエスケープします。

   MyTarget:
      LINE="somevalue"; \
      echo $${LINE}
2
blackpen