我有一种情况需要根据远程文件执行make中的规则。这是我尝试做的一个例子(实际的Makefile在这方面并不复杂):
URL = http://cdn.sstatic.net/stackoverflow/img/favicon.ico
stackoverflow.png: favico.ico modified | check_modified
convert favicon.ico $@
check_modified: modified
@echo Icon was modified. Downloading.
rm -f favicon.ico
wget $(URL)
.PHONY: check_modified
favico.ico: check_modified
modified:
touch -d "`wget --spider -S $(URL) 2>&1 | sed -n 's/.*Modified: //p'`" $@
这个想法是:
modified
的规则应始终运行。该规则的功能是将文件的修改时间更改为与URL指向的修改时间相同。modified
在依赖关系方面表现正常。如果modified
比favicon.ico
更新,我想检索新文件,然后依赖它会导致目标文件重新生成。作为皱纹,在某些应用程序中,我必须手动检索文件。在这些情况下,我想要一个触发并告诉我手动下载文件的规则,但这并不影响构建目标。例如,如果我转换的源图像位于网站登录后面,我需要手动登录该网站并将其下载到固定位置,然后重新运行make。
我尝试过的一切:
modified
不是最近目标。任何智慧的话语?
答案 0 :(得分:3)
你的问题可能是make在运行任何配方之前构建依赖图。因此,当您创建/更新modified
标记文件时,make考虑其最后修改日期并使用它来决定是否应该构建其他目标为时已晚。
您首次观察到的行为(如果目标是最新的,则无法检查URL)可能与您未使用.PHONY
特殊目标的尝试相对应。创建modified
后,make始终将其视为最新,因为它没有先决条件,因此无法过时。
第二种行为(始终检查URL并重建目标,即使修改后的内容不比目标更新)与您发布的内容相对应:check_modified
是先决条件.PHONY
特殊目标,强制使其始终认为它已过时。 stackoverflow.png
和favico.ico
,无论是否直接依赖于check_modified
,因此也始终被视为过时。
解决问题的一个选择是使用递归,双遍,make调用。在第一次运行时,make将构建all
虚假目标(始终),更新modified
标记文件,然后再次调用自身以构建其他目标,这些目标将标记文件作为先决条件并且已过时。因为,对于第二次调用,make rebuild它的依赖图,它将考虑标记文件的最后修改日期。类似的东西:
URL = http://cdn.sstatic.net/stackoverflow/img/favicon.ico
.PHONY: all
all:
touch -d "`wget --spider -S $(URL) 2>&1 | sed -n 's/.*Modified: //p'`" modified
$(MAKE) stackoverflow.ico
stackoverflow.ico: modified
@echo Icon was modified. Downloading.; \
rm -f favicon.ico; \
wget $(URL); \
convert favicon.ico $@
<强>说明:强>
png
无效转换为ico
,因为SO的favicon.ico
图标是复合的,转换为png
会创建两个文件,而不是一个,名为stackoverflow-0.png
和stackoverflow-1.png
,这无关紧要。all
是一个真正的假目标,也是默认目标,因此,每次调用make
(或make all
)时,都会构建它。它首先更新modified
标记文件,然后再次调用make以构建stackoverflow.ico
。stackoverflow.ico
比modified
更新,则第二次make调用不执行任何操作,否则会下载并转换。您的第二个问题(获取有关所需手动操作的消息)完全不同且更易于解决。让我们首先定义一条消息并在文件的配方中回显它:
define DIY_message
Dear user, you should first:
- do this
- and that.
Unless you know it is useless, of course.
endef
export DIY_message
the_remote_file:
@echo "$$DIY_message"
如果使用此目标(make the_remote_file
)或以某种方式取决于the_remote_file
的目标调用make,则会打印该消息:
the_remote_file
不存在,the_remote_file
存在,但就其先决条件而言已过时(如果您已声明其先决条件),the_remote_file
是.PHONY
。注意:使用由define-endef
指定的中间生成变量可以使格式化的多行消息更容易。