从URL列表下载文件列表作为makefile中的先决条件

josealberto4444

我想要一个用于编译项目的makefile,如果缺少某些文件(二进制文件),则需要下载这些文件(因为使用git跟踪它们不是一个好主意)。

我有一个URL列表和一个给定名称的列表(并且我希望能够选择名称来保存它们,因为我无法控制URL名称,并且大多数名称很糟糕且没有描述性)。假设文件将始终相同,或者我们不在乎服务器中的文件是否更改(我们无需再次下载它们)。

所以我的想法是在我的makefile文件中写这样的东西:

files = one two three four

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

但是我希望每个都可以下载(如果它们还不存在的话),并且每个都可以从其自己的URL下载,所以我需要对$(files)元素进行迭代之类的操作。

我将把混合python代码和我从makefiles知道的想法写下来。我知道这是垃圾,但是我不知道有什么其他方式可以做到(问题是基本上如何正确编写),而且我认为这很容易理解。

urls = url1 url2 url3 url4

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

因此,问题是:我该怎么做?

我已经看了一段时间的make文档,没有多次写文件名就找不到正确的方法(我认为应该避免使用文件名,而应该使用变量)。也许罐装食谱就是这样,但我看不出怎么做。

雷诺·帕卡莱特

有几种方法可以做您想要的。警告:它们有些棘手,因为它们使用GNU make的高级功能:

解决方案1:

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)))\
)

我用回声代替了配方,以便于测试:

$ 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

说明:

DOWNLOAD_rule多行变量是哪里下载操作模板规则$(1)表示文件名和$(2)代表相应的URL。

您可以执行$(1)$(2)的替换,使用DOWNLOAD_rulemake实例化结果作为make语法:

$(eval $(call DOWNLOAD_rule,one,url1))

这就像您写的一样:

one:
    @echo 'curl -Lo one url1'

foreach功能允许循环单词列表。所以:

$(foreach f,$(files),$(eval $(call DOWNLOAD_rule,$(f),url1)))

将实例化所有文件的规则...除了所有URL的URL相同(url1)外。不是你想要的。

为了获得对应于每个文件的URL,我们可以evalforeach循环中函数进行两次不同的调用

  • 第一个使用当前文件名和中的第一个URL实例化规则的规则$(urls)
  • 第二个从中删除第一个单词,$(urls)然后将结果重新分配给urls

请注意:=分配,它们是必不可少的。默认值=(递归扩展)在这里不起作用。

$(wordlist 2,$(words $(urls)),$(urls)) 可能看起来很复杂,但事实并非如此:

  • $(wordlist s,e,l)作为字的数目扩展se在列表l(字被编号从1到的长度l
  • $(words l) 扩展为列表中的单词数 l

所以,如果$(urls)是,例如url2 url3 url4

  • $(words $(urls)) 扩展为3
  • $(wordlist 2,$(words $(urls)),$(urls))扩展为,url3 url4因为它与$(wordlist 2,3,url2 url3 url4)

解决方案2:

也可以evalDOWNLOAD_rule变量中包装第二个变量,但是要考虑的另一个方面是:在传递给外壳之前,使用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作为常规make语法分析结果时会再次对其进行扩展。$$是一种保护变量引用不受第一次扩展影响的方法,这样eval在的四个迭代期间实例化foreach是:

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))

它将完全满足我们的要求。如果没有,$$它将是:

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有两个扩展,$$通常需要使用它们来逃避第一个扩展

解决方案3:

我们还可以为每个文件(<file>-url声明一个变量来存储URL,并为设置这些变量和文件列表(files声明一个

# 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:

最后,我们可以使用John Graham-Cumming出色的GNU Make标准库gmsl及其关联数组来完成与解决方案#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))))

本文收集自互联网,转载请注明来源。

如有侵权,请联系 [email protected] 删除。

编辑于
0

我来说两句

0 条评论
登录 后参与评论

相关文章

Makefile先决条件列表中的分号是什么?

Makefile:如何为两个文件列表设置先决条件

从url下载文件(在列表中)

makefile:先决条件$(变量)中的%模式

Makefile 先决条件中的变量分配

指定输入源(而不是中间体)作为 Makefile 中目标的先决条件

Makefile,先决条件自动变量中的替代路径

为什么先决条件的顺序在 makefile 中很重要?

如何在 Makefile 目标中重复相同的先决条件?

如何创建函数以生成make中目标的先决条件列表

IFTTT-从URL下载文件列表

关于自动生成Makefile先决条件

makefile 不扩展动态先决条件

规则之前的Makefile先决条件

Makefile 仅识别更改的先决条件,而不识别新的先决条件

makefile 通配符先决条件多次获取同一个文件

如何使用Selenium Webdriver通过URL列表下载文件

使用 wget 从 index.html url 下载文件列表

搜索文件列表中的所有下载文件

Makefile的同一目标中是否可能有多个先决条件模式?

GNU制作通配符扩展的目标和先决条件顺序的显式列表

先决条件

makefile:: *** 先决条件不能在配方中定义。停止

如何设置Makefile目标取决于模式先决条件?

Makefile:将PHONY目标声明为配方先决条件

makefile 目标比先决条件更新,但会重新完成

具有非语音先决条件的Makefile .PHONY目标

Makefile:如果不存在则忽略先决条件

具有动态先决条件的动态 Makefile 目标