希望することを行うにはいくつかの方法があります。警告:彼らが作るGNUの高度な機能を使用するため、彼らは少しトリッキーです:
溶液#1:
$ make -j
curl -Lo one url1
curl -Lo four url4
curl -Lo three url3
curl -Lo two url2
command to do when files are present
:私は簡単にテストのためにエコーでレシピを置き換え
files := one two three four
urls := url1 url2 url3 url4
main: $(files)
@echo 'command to do when files are present'
# $(1): file name
# $(2): url
define DOWNLOAD_rule
$(1):
@echo 'curl -Lo $(1) $(2)'
endef
$(foreach f,$(files),\
$(eval $(call DOWNLOAD_rule,$(f),$(firstword $(urls))))\
$(eval urls := $(wordlist 2,$(words $(urls)),$(urls)))\
)
説明:
DOWNLOAD_rule
複数行va riableはダウンロード操作のテンプレートルールです。$(1)
はファイル名を表し、$(2)
は対応するURLを表します。
あなたはDOWNLOAD_rule
に$(1)
と$(2)
の置換を実行し、とメイク構文として結果をインスタンス化することができます:あなたが書いたかのようにこれは同じである
$(eval $(call DOWNLOAD_rule,one,url1))
:
one:
@echo 'curl -Lo one url1'
foreach
関数は単語のリストをループすることができます。だから、:
$(foreach f,$(files),$(eval $(call DOWNLOAD_rule,$(f),url1)))
は、URLはすべてのために(url1
)同じになることを除いて...すべてのファイルのルールをインスタンス化します。あなたが望むものではありません。
各ファイルに対応するURLを取得するために、我々は我々のforeach
ループでeval
機能への2つの異なる呼び出しを置くことができます。
- 現在のファイル名とを持つルールをインスタンス化する最初のもの最初のURLは
$(urls)
,
- で、最初の単語を
$(urls)
から削除し、結果をurls
に再割り当てします。
割り当ては、必須です。デフォルトの=
(再帰的拡張)はここでは機能しません。
$(wordlist 2,$(words $(urls)),$(urls))
が複雑に見えるかもしれないが、それはありません:
$(wordlist s,e,l)
は
$(words l)
は数として展開(単語が1からl
の長さに番号付けされる)リストl
でe
にワード数s
として展開しますリスト内の単語l
したがって、$(urls)
が、 G、url2 url3 url4
:
それすることも可能である:それは$(wordlist 2,3,url2 url3 url4)
溶液#2と同じであるため、3
$(wordlist 2,$(words $(urls)),$(urls))
がurl3 url4
ように膨張する
$(words $(urls))
が膨張2番目のをDOWNLOAD_rule
変数にパックしますが、考慮すべきもう1つの側面があります。 cipeはシェルに渡される直前にmakeによって展開されます。分析の最初のパスの間に展開されているターゲット固有の変数(url
)は、これを解決します files := one two three four
urls := url1 url2 url3 url4
main: $(files)
@echo 'command to do when files are present'
# $(1): file name
define DOWNLOAD_rule
$(1): url := $$(firstword $$(urls))
$(1):
@echo 'curl -Lo $(1) $$(url)'
urls := $$(wordlist 2,$$(words $$(urls)),$$(urls))
endef
$(foreach f,$(files),$(eval $(call DOWNLOAD_rule,$(f))))
はDOWNLOAD_rule
の定義に$$
注eval
は、そのパラメータを拡大し、拡大していきます作るので、それらが必要とされています結果を通常のmake構文として解析すると、2回目です。まさに私たちがやりたいだろう
one: url := $(firstword $(urls))
one:
@echo 'curl -Lo one $(url)'
urls := $(wordlist 2,$(words $(urls)),$(urls))
two: url := $(firstword $(urls))
two:
@echo 'curl -Lo two $(url)'
urls := $(wordlist 2,$(words $(urls)),$(urls))
three: url := $(firstword $(urls))
three:
@echo 'curl -Lo three $(url)'
urls := $(wordlist 2,$(words $(urls)),$(urls))
four: url := $(firstword $(urls))
four:
@echo 'curl -Lo four $(url)'
urls := $(wordlist 2,$(words $(urls)),$(urls))
:$$
は何foreach
の4回の反復中eval
によってインスタンス化されることであるように、最初の展開から、私たちの変数の参照を、保護する方法です。 $$
せず、それは次のようになりますが:
one: url := url1
one:
@echo 'curl -Lo one '
urls := url2 url3 url4
two: url := url1
two:
@echo 'curl -Lo two '
urls := url2 url3 url4
three: url := url1
three:
@echo 'curl -Lo three '
urls := url2 url3 url4
four: url := url1
four:
@echo 'curl -Lo four '
urls := url2 url3 url4
はこのことを忘れないでください:eval
を使用している場合がある2つの拡張であり、$$
は頻繁に最初のものをエスケープするために必要とされます。我々はまた、URLを格納するファイル(<file>-url
)ごとに一つの変数を宣言することができます
、およびこれらの変数とファイルのリストを設定するマクロ(files
):
溶液#3
# Set file's URL and update files' list
# Syntax: $(call set_url,<file>,<url>)
set_url = $(eval $(1)-url := $(2))$(eval files := $$(files) $(1))
$(call set_url,one,url1)
$(call set_url,two,url2)
$(call set_url,three,url3)
$(call set_url,four,url4)
main: $(files)
@echo 'command to do when files are present'
# $(1): file name
define DOWNLOAD_rule
$(1):
@echo 'curl -Lo $(1) $$($(1)-url)'
endef
$(foreach f,$(files),$(eval $(call DOWNLOAD_rule,$(f))))
ソリューション#4:
最後に、我々は優れたGNU Make Standard Library(を使用することができます0)John Graham-Cummingとその連想配列は、解#3とほぼ同じです。私たちは、例えば、キーと値としてURLなどのファイル名でurls
という名前の連想配列を定義することができます(サーバー上の)ファイルの変更を行います
include gmsl
$(call set,urls,one,url1)
$(call set,urls,two,url2)
$(call set,urls,three,url3)
$(call set,urls,four,url4)
files := $(call keys,urls)
main: $(files)
@echo 'command to do when files are present'
# $(1): file name
define DOWNLOAD_rule
$(1):
@echo 'curl -Lo $(1) $$(call get,urls,$(1))'
endef
$(foreach f,$(files),$(eval $(call DOWNLOAD_rule,$(f))))
を、あなたは再びそれらを取得する必要がありますか?その場合は、一種の依存関係管理(Apache Ivyなど)を考えたり、makefileをgradleスクリプトで置き換えることができます。 – pitseeker
いいえ、変更されません(またはそうしても気にしません)。私は反射するように質問を編集します、ありがとう! – josealberto4444