2017-11-27 17 views
6

プロジェクトをコンパイルするためのメイクファイルを用意したいと思います。欠けている場合はいくつかのファイル(バイナリ)をダウンロードする必要があります。 gitでそれらを追跡する。メイクファイルの前提条件としてURLのリストからファイルのリストをダウンロードする

私はURLのリストと指定された名前のリストを持っています(URL名を制御することができないので、名前を保存するために名前を選ぶことができます。 -descriptive)。ファイルが常に同じであるか、サーバーで変更されても気にしない(つまり、再度ダウンロードする必要はありません)としましょう。

だから私の考えは私のメイクファイルでこのような何かを書くことだった:

files = one two three four 

main : $(files) 
    command to do when files are present 

を彼らは既に存在していない場合、私はそれらのそれぞれをダウンロードすることにしたい、と独自のURLから各1ので、私$(ファイル)の要素の繰り返しのようなものが必要です。

私は自分の考えでPythonコードを混ぜて、私がmakefileから知っているアイデアを書きます。私はそれがごみであることを知っていますが、私はそれを行うための他の方法は分かりません(質問は基本的にうまく書ける方法です)。

urls = url1 url2 url3 url4 

for i in len(files): 
    $(files)[i] : 
     curl -Lo $(files)[i] $(urls)[i] 

したがって、どうすればよいですか?

私はしばらくドキュメントを探していましたが、ファイル名を何度も書き込まないと適切な方法を見つけることができませんでした(避けるべきで、代わりに変数を使用する必要があると思います)。たぶんcanned recipesは方法ですが、私はどのように見ることができません。非常に愚かなソリューションでした

+0

を、あなたは再びそれらを取得する必要がありますか?その場合は、一種の依存関係管理(Apache Ivyなど)を考えたり、makefileをgradleスクリプトで置き換えることができます。 – pitseeker

+0

いいえ、変更されません(またはそうしても気にしません)。私は反射するように質問を編集します、ありがとう! – josealberto4444

答えて

1
FILES := file1 file2 file3 

main : $(FILES) 
    command to do when files are present 

file1: firstuglyurl 
file2: seconduglyurl 
file3: thirduglyurl 

$(FILES): 
    curl -Lo [email protected] $< 

[EDIT]、私は私が考えていたのか分かりません。これを試してみてください:

FILES := file1 file2 file3 

main : $(FILES) 
    command to do when files are present 

file1: URL:=firstuglyurl 
file2: URL:=seconduglyurl 
file3: URL:=thirduglyurl 

$(FILES): 
    curl -Lo [email protected] $(URL) 

マップ(URL =>ファイル名)がファイル内にあり、あなたが手でメイクファイルでそれを維持するためにしたくない、あなたはあまり問題なくインポート、それを作ることができた場合は、形式を教えてください。

これは、存在するが期限切れのファイル、つまり最新のバージョンのファイルがURLに存在するかどうかをチェックしないことに注意してください(おそらく実行できますが、扱いにくいです...)。

+0

私は、これが欠落している前提について文句を言うと思いました。つまり、一番最初に構築するルールはありません。 – lockcmpxchg8b

+0

Ahh ..しかし、.PHONYをURLに依存させることは、それを修正します。 – lockcmpxchg8b

+0

curl呼び出しに '-R/- remote-time'を追加することもできます。ちょうど私たちが日付のあるソースから引っ張っている場合は...クロックが比較的よく同期していると信じることができればです。 – lockcmpxchg8b

3

希望することを行うにはいくつかの方法があります。警告:彼らが作る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の長さに番号付けされる)リストleにワード数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)))) 
      
  • +0

    コメントでコードを正しく書式設定する方法を理解できません... '$(foreach)'の2つの最初の '$(eval)'を 'urls:= $(wordlist 2、x、 $(urls)) 'を' DOWNLOAD_rule'の本文に追加します。 (x> URL数でURLとファイルがあります。 – VannTen

    +0

    @VannTenあなたは正しいですが、検証されていないハードワイヤードの上限(「x」)は好きではありません。見つけにくいバグ。 –

    +0

    @VannTenまた、 '$(urls)'から最初の単語を抽出するには、最初の 'eval'が必要です。 –

    関連する問題