make

时间:2015-12-09 23:00:00

标签: makefile

我有一种情况需要根据远程文件执行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在依赖关系方面表现正常。如果modifiedfavicon.ico更新,我想检索新文件,然后依赖它会导致目标文件重新生成。

作为皱纹,在某些应用程序中,我必须手动检索文件。在这些情况下,我想要一个触发并告诉我手动下载文件的规则,但这并不影响构建目标。例如,如果我转换的源图像位于网站登录后面,我需要手动登录该网站并将其下载到固定位置,然后重新运行make。

我尝试过的一切:

  • 如果目标是最新的,则无法检查URL,或
  • 始终检查网址并重建目标,即使modified不是最近目标。

任何智慧的话语?

1 个答案:

答案 0 :(得分:3)

你的问题可能是make在运行任何配方之前构建依赖图。因此,当您创建/更新modified标记文件时,make考虑其最后修改日期并使用它来决定是否应该构建其他目标为时已晚。

您首次观察到的行为(如果目标是最新的,则无法检查URL)可能与您未使用.PHONY特殊目标的尝试相对应。创建modified后,make始终将其视为最新,因为它没有先决条件,因此无法过时。

第二种行为(始终检查URL并重建目标,即使修改后的内容不比目标更新)与您发布的内容相对应:check_modified是先决条件.PHONY特殊目标,强制使其始终认为它已过时。 stackoverflow.pngfavico.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.pngstackoverflow-1.png,这无关紧要。
  • all是一个真正的假目标,也是默认目标,因此,每次调用make(或make all)时,都会构建它。它首先更新modified标记文件,然后再次调用make以构建stackoverflow.ico
  • 如果stackoverflow.icomodified更新,则第二次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指定的中间生成变量可以使格式化的多行消息更容易。