2017-01-01 3 views
1

私は、非再帰的なmakeシステムの一般的なルールを定義するのが難しいです。むしろ、私はあまりにも多くの既存の材料を再現するよりも、さらに読書については、名前が単純に展開された変数から計算される変数を使用して再帰的に展開された変数を定義する

背景

this earlier questionを参照してください、かなりよく地面を覆っており、このシステムを構築する場合、以前に私を助けてくれました。

私が構築しているmakeシステムでは、システムコンポーネント間の依存関係を定義したいと思います。コンポーネントAはコンポーネントBに依存しています。その後、Aビルド・ステップで必要となる前にBビルド・プロセスの製品が構築されていることを確認するためにmakeシステムを終了します。 )しかし、私の使用事例では、使いやすさとビルド性能の間の快適なバランスポイントを満たしています。

システムで扱わなければならない問題は、メイクファイルの読み込み順序を制御できないことです。実際問題ではありません。しかし、このため、初期ロードされたメイクファイルで定義されたコンポーネントは、未読メークファイルで定義されたコンポーネントに依存することがあります。

すべてのコンポーネント定義メイクファイルに共通パターンを適用できるように、各コンポーネントは$(component_name)_SRCなどの変数を使用します。これは、再帰的ではない(ただし再帰的に含まれる)makeシステムの共通の解決策です。

GNU makeのさまざまな種類の変数については、the manualを参照してください。まとめると、単純に拡張された変数(SEV)は、makefileが読み込まれるときに展開され、命令型プログラミング言語に類似した動作を示します。再帰的に拡張された変数(REV)は、すべてのmakefileが読み込まれた後、makeの第2段階で展開されます。

問題

これらのコンポーネントが表すファイルのリストに依存-上のコンポーネントのリストをオンにしようとしたときに特定の問題が発生します。

私は実際のシステムの詳細をたくさん残しているこの実行可能な例に私のコードを書き留めました。私はこれが物質を失うことなく問題を実証するのに十分簡単だと思います。

rules.mk:

$(c)_src    := $(src) 
$(c)_dependencies  := $(dependencies) 

### This is the interesting line: 
$(c)_dependencies_src := $(foreach dep, $($(c)_dependencies), $($(dep)_src)) 

$(c) : $($(c)_src) $($(c)_dependencies_src) 
     @echo $^ 

のMakefile:

.PHONY: foo_a.txt foo_b.txt bar_a.txt hoge_a.txt 

### Bar 
c   := bar 
src   := bar_a.txt 
dependencies := 

include rules.mk 

### Foo 
c   := foo 
src   := foo_a.txt foo_b.txt 
dependencies := bar hoge 

include rules.mk 

### Hoge 
c   := hoge 
src   := hoge_a.txt 
dependencies := bar 

include rules.mk 

これらを与えることを実行します:

$ make foo 
foo_a.txt foo_b.txt bar_a.txt 
$ 

hoge_a.txtが原因で、出力に含まれていませんfoo_dependenciesがSEVと定義されている場合、hoge_srcはまだ存在しません。

読まれているすべてのmakefile後

拡張は、回転数が解決することができるはずの問題であり、私は以前REVとして$(c)_dependencies_srcを定義しようとしましたが、それが動作しないのいずれか$(c)ので、その後の置換時間、ない定義で展開されていますそれはもはや正しい値を保持しません。

なぜターゲット固有の変数を使用していないのだろうかと疑問に思っている人は、このマニュアルで説明されているターゲットのすべての前提条件に変数を適用すると、 。

私が知りたいのです:

  1. は、この特定の問題への解決策はありますか? (つまり、その行が私が望むものを達成するための簡単な方法がありますか?)
  2. このようなmakeシステムを構築するより典型的な方法がありますか? (つまり、複数のメイクファイルからコンポーネントをロードし、それらのコンポーネント間の依存関係を定義する単一のメイクインスタンス)
  3. 複数のソリューションがある場合、それらの間のトレードオフは何ですか?

最終的なコメント:私の質問を書いたように、REV定義を構築するためにevalを使用することが可能な解決策があるかもしれないことを認識し始めました。そうでなければ、私は将来のサーチャーのために質問をする価値があると思っていました。さらに、このアプローチや他のアプローチに関する経験豊富なユーザーの考えを聞きたいと思います。

+0

'$(c)_dependencies_src'を設定するときに' = 'の代わりに':= 'を使用しているのはなぜですか?ここで '='を使うと、あなたの問題を解決できます。 – MadScientist

+0

個人的には、 'c:= foo'を割り当ててルールファイルを指定した後、' c:= bar'を割り当て、ルールファイルを含むようなグローバル変数を使用するシステムは決して作成しません。私は 'target + = foo'、' foo_c:= foo'、 'foo_src:= foo.x'など' targets + = bar'、 'bar_c:= bar'、' bar_src := bar.x'などです。これにより、同じ変数名を設定してリセットする前にそれらを確実に使用することがなくなります。 – MadScientist

+0

投稿した例で試してみましたか?私が言ったように、少なくともREVは解決できなければならず、以前は$(c)_dependencies_srcをREVとして定義しようとしました... " –

答えて

0

短い答えは、あなたが求めている質問のための良い解決策はありません。変数の途中での展開をやめ、後で延期することはできません。それだけでなく、必要な変数参照を含むように変数の値を取得できたとしても、前提条件リストで変数を使用するため、次の行では前提条件リストの一部として完全に展開されますそれであなたに何も得られないでしょう。

前提条件の拡張を延期する方法は1つだけあり、secondary expansion機能を使用することです。

$(c)_src    := $(src) 
$(c)_dependencies  := $(dependencies) 

.SECONDEXPANSION 
$(c) : $($(c)_src) $$(foreach dep, $$([email protected]_dependencies), $$($$(dep)_src)) 
     @echo $^ 

(未テスト)のようにする必要があります。これにより、$(c)_dependencies_srcの問題は、それを一切定義せずに前提条件のリストに直接入れるだけで、二次的な展開となります。

私が上記のコメントに書いたように、私は個人的にこのように機能するシステムを設計しませんでした。私は、すべての変数が名前空間(通常はターゲット名を前にして)を使用して作成され、最後に、すべての変数が定義された後、単一の "rules.mk"すべてのそれらの変数は、ルールを構築する可能性が最も高い(あなたのレシピがすべてシンプルでない限り)evalを使用します。

ので、何かのように:

targets := 

### Bar 
targets += bar 
bar_c   := bar 
bar_src   := bar_a.txt 
bar_dependencies := 

### Foo 
targets += foo 
foo_c   := foo 
foo_src   := foo_a.txt foo_b.txt 
foo_dependencies := bar hoge 

### Hoge 
targets += hoge 
hoge_c   := hoge 
hoge_src   := hoge_a.txt 
hoge_dependencies := bar 

# Now build all the rules 
include rules.mk 

そしてrules.mkにあなたのような何かを見るでしょう:

define make_c 
$1 : $($1_src) $(foreach dep, $($1_dependencies), $($(dep)_src)) 
     @echo $$^ 
endif 

$(foreach T,$(targets),$(eval $(call make_c,$T))) 
あなたの変数に注意している場合でも targetの設定を取り除くことができ

このような名前を追加すると、rules.mk

targets := $(patsubst %_c,%,$(filter %_c,$(.VARIABLES))) 

異なるターゲットで同じコンポーネントを使用できるようにするには、2つの異なるコンポーネントを区別するために名前空間にさらに多くの要素を追加するだけです。

+0

変数を拡張していたのはルール定義だったことを指摘していただきありがとうございます。私はここでの厳密に宣言的ではないアプローチの嫌悪感を理解していますが、現在のアプローチを有効にする方法があるかどうかを見たいと思っています。当分の間。名前空間を動的に構築するには、コンポーネント・ライターからコンポーネント・ユーザーにそれを管理する責任が移るので、いくつかの価値がありますが、この問題はトレードオフの1つです。 –

関連する問題