如何在GNU Make中使用SECONDEXPANSION通配符规则?

huangapple go评论45阅读模式
英文:

How do I wildcard a rule with SECONDEXPANSION in GNU Make?

问题

# Docker Chain
src_files:=$(shell find src/ -name '*.py')
image_tags=$(shell find dkr/ -name '$(PROJECT).*.dockerfile' | xargs -n 1 basename -s '.dockerfile')

dkr/%.dockerfile: $(src_files)
  docker build . -f $@ -t $*

.SECONDEXPANSION:
$(PROJECT).base: dkr/$$@.dockerfile

.SECONDEXPANSION:
$(PROJECT).%: $(PROJECT).base | dkr/$$*.dockerfile

publish-%:
  $(MAKE) $*
  ./scripts/$@.sh $(RESOURCE_PREFIX) $* $(REGION)

publish:
  $(foreach tag, $(image_tags), $(MAKE) publish-$(tag))
英文:
# Docker Chain
src_files:=$(shell find src/ -name '*.py')
image_tags=$(shell find dkr/ -name '$(PROJECT).*.dockerfile' | xargs -n 1 basename -s '.dockerfile')

dkr/%.dockerfile: $(src_files)
  docker build . -f $@ -t $*

.SECONDEXPANSION:
$(PROJECT).base: dkr/$$@.dockerfile

.SECONDEXPANSION:
$(PROJECT).foo: $(PROJECT).base | dkr/$$@.dockerfile

.SECONDEXPANSION:
$(PROJECT).bar: $(PROJECT).base | dkr/$$@.dockerfile

publish-%:
  $(MAKE) $*
  ./scripts/$@.sh $(RESOURCE_PREFIX) $* $(REGION)

publish:
  $(foreach tag, $(image_tags), $(MAKE) publish-$(tag))

I would like to write the above as:

# Docker Chain
src_files:=$(shell find src/ -name '*.py')
image_tags=$(shell find dkr/ -name '$(PROJECT).*.dockerfile' | xargs -n 1 basename -s '.dockerfile')

dkr/%.dockerfile: $(src_files)
  docker build . -f $@ -t $*

.SECONDEXPANSION:
$(PROJECT).base: dkr/$$@.dockerfile

.SECONDEXPANSION:
$(PROJECT).%: $(PROJECT).base | dkr/$$@.dockerfile

publish-%:
  $(MAKE) $*
  ./scripts/$@.sh $(RESOURCE_PREFIX) $* $(REGION)

publish:
  $(foreach tag, $(image_tags), $(MAKE) publish-$(tag))

However, the wildcarding in the rule (via '%') does not work. I suppose I have misunderstood rule substitution, and am guessing it is due to the SECONEXPANSION.

But, my make intuition is telling me this should work, and it should be good.

How would I perform substitution in this scenario?

答案1

得分: 0

代码上的问题出在上面,而不是“其他地方”。此外,你对.SECONDEXPANSION的应用是正确的;问题不在那里。在这里:

在Makefile中,你可以有一个依赖规范,而不需要为其提供任何配方,就像你的第一个例子中一样:

$(PROJECT).foo: $(PROJECT).base | dkr/$$@.dockerfile

但是,如果你尝试使用模式(%)来创建这样的依赖关系(没有配方),你就无法实现(Make使用这样的东西来表示其他东西)。要创建“模式规则”,你必须提供一个配方。如果你实际上没有一个配方,那就提供虚拟的配方,即在依赖关系行之后加上分号。

所以

$(PROJECT).%: $(PROJECT).base | dkr/$$@.dockerfile ;

这将解决你的问题。

顺便说一下,我不明白为什么你需要那些“顺序前提条件”(在|之后)。它们用于防止目标仅因为先决条件更新而重新构建。由于这些目标没有配方,因此没有必要设置顺序前提条件。所以只需执行

$(PROJECT).%: $(PROJECT).base dkr/$$@.dockerfile ;

英文:

The problem is in the code above, not "elsewhere". Also, your application of .SECONDEXPANSION is correct; the problem is not there. It is here:

You can have a dependency specification in a makefile, without any recipe to it, like in your first example:

$(PROJECT).foo: $(PROJECT).base | dkr/$$@.dockerfile

But, if you try to have such a dependency (without a recipe), with a pattern (%), you can't (Make uses such a thing for something else). To have a "pattern rule", you must supply a recipe. If you don't really have a recipe, then supply the dummy recipe, which is a semicolon after the dependency line.

So

$(PROJECT).%: $(PROJECT).base | dkr/$$@.dockerfile ;

and that will solve your problem.

By the way, I don't see why you need those "order prerequisites" (after the |). They are used to prevent the target from rebuilding solely because the prerequisite is newer. Since these targets do not have a recipe, there is no point in having order prerequisites. So just do

$(PROJECT).%: $(PROJECT).base dkr/$$@.dockerfile ;

huangapple
  • 本文由 发表于 2023年2月10日 07:48:00
  • 转载请务必保留本文链接:https://go.coder-hub.com/75405620.html
匿名

发表评论

匿名网友

:?: :razz: :sad: :evil: :!: :smile: :oops: :grin: :eek: :shock: :???: :cool: :lol: :mad: :twisted: :roll: :wink: :idea: :arrow: :neutral: :cry: :mrgreen:

确定