假设我对make做了一些非常规的使用。此外,假设我已经在这个用法中提出了一个名称方案,它对make以外的工具非常有用,并且几乎完全适合于make范例。
我几乎可以利用内置的make来完成这个任务,并且正在寻找一些魔法来使它在系统的语义和语法中“正常工作”。
现在,我有一个可构建的过程,具体如下:
# "<-" = "depends on"
foo.bar.biz.baz.new <- foo.bar.biz.baz.extension bar.biz.baz.new
bar.biz.baz.new <- bar.biz.baz.extension biz.baz.new
biz.baz.new <- biz.baz.extension baz.new
baz.new <- baz.extension
# and the following rules should suffice, where $(magic ...) is a stand-in for what I'd like to do:]
SHELL:=/usr/bin/env bash
.SECONDEXPANSION
%.new: $$*.extension $(magic $$*)
...
build: foo.bar.biz.baz.new我要找的是一些神奇的东西:
a...b -> ...c if ... != ""
# so, it chops off the prefix (dot-delimited), a
# and swaps the suffix only if something is present other than the suffix我认为这可能是:
$(filter-out .c, $(patsubst %,%.c $(not-prefix $$*)))如果没有-前缀存在,我想知道是否有一些内置的-或多或少地完成了这一任务?
或者,是否有一些真正的紧凑的巴什主义,可以做到这一点?
例如:
$(shell echo "$$*" | sed -E 's/[^.]*(.*)\.[^.]*$$/\1.new/' | grep -v -E '^\.new$$')是超级多风和冗长,但也许有一些紧凑的方式来做到这一点?
到目前为止,我想出的最可读的是:
%.new: $$*.extension $(filter-out .new, $(shell echo "$$@" | cut -d '.' -f 1 --complement))更新树构建递归问题的最小可验证示例:
%.ext:
@touch $@
.SECONDEXPANSION:
%.new: $$*.ext $(filter-out new, $(shell echo "$$@" | cut -d '.' -f 1 --complement))
@echo "@: $@"
@echo "<: $<"
@echo "^: $^"
@echo $(filter-out new, $(shell echo "$@" | cut -d '.' -f 1 --complement))$ make descendant.ancestor.new
@: descendant.ancestor.new
<: descendant.ancestor.ext
^: descendant.ancestor.ext
ancestor.new
rm descendant.ancestor.ext接下来,我将第二个"$“符号添加到规则中,以便在第二个展开期间执行它:
%.ext:
@touch $@
.SECONDEXPANSION:
%.new: $$*.ext $$(filter-out new, $$(shell echo "$$@" | cut -d '.' -f 1 --complement))
@echo "@: $@"
@echo "<: $<"
@echo "^: $^"
@echo $(filter-out new, $(shell echo "$@" | cut -d '.' -f 1 --complement))产生的结果:
$ make descendant.ancestor.new
make: *** No rule to make target 'descendant.ancestor.new'. Stop.最后,我认为这应该是:
.SECONDEXPANSION:
%.new: $$*.ext | $$(filter-out new, $$(shell echo "$$@" | cut -d '.' -f 1 --complement))但是,相反,我所做的让它“只是起作用”是:
%.ext:
@touch $@
.SECONDEXPANSION:
%.new: $$*.ext .FORCE
@echo "@: $@"
@echo "<: $<"
@echo "^: $^"
@$(eval prior=$(filter-out new, $(shell echo "$@" | cut -d '.' -f 1 --complement)))
@$(if $(prior),$(MAKE) $(prior))
@echo "ta-da: idempotent, depth first tree recursion @:$@"
.FORCE:这会产生比规则线更脆弱的行为:
$ make -s branch.root.new
@: branch.tree.new
<: branch.tree.ext
^: branch.tree.ext .FORCE
@: tree.new
<: tree.ext
^: tree.ext .FORCE
ta-da: idempotent, depth first tree recursion @:tree.new
ta-da: idempotent, depth first tree recursion @:branch.tree.new发布于 2020-12-18 20:25:21
好的,谢谢你澄清你要找的东西。因此,我没有任何我会认为“非常简单”的东西,但是您可以完全使用GNU make使用以下方法:
e =
sp = $e $e
magic1 = $(if $(filter-out 1,$(words $(subst ., ,$1))),$1,)
magic = $(call magic1,$(subst $(sp),.,$(wordlist 2,1000,$(subst ., ,$1))))现在,在任何您希望“魔术”发生的地方,调用magic函数:
.SECONDEXPANSION:
%.new: $$*.ext $$(call magic,$$@)如果magic1宏的参数大于1 .,则扩展到它的参数,否则扩展到空字符串。magic宏去掉第一个“前缀”,并使用该值调用magic1。
也许有更简单的方法来做到这一点,我并没有想出一个从我的头顶。
此外,我没有回顾你编辑的问题,所以我不确定你在那里添加的内容是否会在这里起作用。
发布于 2020-12-18 16:52:55
这里的问题是,大多数构建系统依赖于稳定的前缀和后缀,只有变化的茎(中间部分)。
在这里,您有一个任意变化的前缀,以及中间部分。因此,例如,在第一种依赖情况下,bar.biz.baz是所有名称中的公共词干。这是武断的。但是,所涉及的每个名称都有一个独立的任意前缀,如foo。
为了避免与该工具发生冲突,我将尝试将foo和biz.bar.baz以及其他每一对代码编码在一些变量中,这些变量充当了这些信息的主要来源。
样品制作。在这个解决方案中,我们只使用call、firstword、secondword一个字符的subst、foreach和eval。
UNITS := foo@biz.bar.baz bar@biz.baz biz@baz
# $(call FIRST, foo@bar) -> foo
FIRST = $(firstword $(subst @, ,$(1)))
# $(call REST, foo@bar) -> bar
REST = $(lastword $(subst @, ,$(1)))
TARGETS := $(foreach U,$(UNITS),$(call FIRST,$(U)).$(call REST,$(U)).new)
DEPS := $(foreach U,$(UNITS),$(call FIRST,$(U)).$(call REST,$(U)).extension) \
$(foreach U,$(UNITS),$(call REST,$(U)))
.PHONY: all $(TARGETS) $(DEPS)
all: $(TARGETS)
define RULE
$(1).$(2).new: $(1).$(2).extension $(2)
@echo BUILD $$@ '<-' $$^
endef
$(foreach U,$(UNITS),\
$(eval $(call RULE,$(call FIRST,$(U)),$(call REST,$(U)))))输出:
$ make
BUILD foo.biz.bar.baz.new <- foo.biz.bar.baz.extension biz.bar.baz
BUILD bar.biz.baz.new <- bar.biz.baz.extension biz.baz
BUILD biz.baz.new <- biz.baz.extension baz另一种方法,使用计算变量名。这里,除了模拟数据结构的计算变量之外,我们只使用foreach、call和eval。除了嵌套变量展开之外,根本没有字符串处理:
UNITS := mercury mars venus
mercury.head := foo
mercury.tail := biz.bar.baz
mars.head := bar
mars.tail = biz.baz
venus.head := biz
venus.tail := baz
TARGETS := $(foreach U,$(UNITS),$($(U).head).$($(U).tail).new)
DEPS := $(foreach U,$(UNITS),$($(U).head).$($(U).tail).extension) \
$(foreach U,$(UNITS),$($(U).tail))
.PHONY: all $(TARGETS) $(DEPS)
all: $(TARGETS)
define RULE
$(1).$(2).new: $(1).$(2).extension $(2)
@echo BUILD $$@ '<-' $$^
endef
$(foreach U,$(UNITS),\
$(eval $(call RULE,$($(U).head),$($(U).tail))))发布于 2020-12-18 10:59:12
我要找的是一些神奇的东西: A.b -> ...c如果.= "“# so,它将去掉前缀(以点分隔),a#只在后缀以外的东西存在时才交换后缀。
我不完全理解您想要执行的操作,但是GNUmake表工具包有一些实用的字符串操作,尽管它的名称是:
include gmtt.mk
TEST := $(call glob-match,aprefix.thensomething.somemore.thenapostfix,aprefix.*.*apostfix)
$(info $(TEST))
$(if $(TEST),$(info Yes, string looks like),$(info No, string doesn't look like))
$(info aprefix..apostfix)
$(if $(TEST),$(info The variable contents of the string is "$(word 2,$(TEST))" and "$(word 4,$(TEST))"))输出:
aprefix. thensomething . somemore.then apostfix
Yes, string looks like
aprefix..apostfix
The variable contents of the string is "thensomething" and "somemore.then" PS:我想指出的是,模式中的.*序列并不构成0..n任意字符的正则序列,而是一个glob模式,其中*单独表示0.n个任意字符的重复。.在这里是文字的。
编辑:下面是一个具有动态规则的解决方案(要真正生成它们,请用eval替换info )
include gmtt/gmtt.mk
gen-rules = \
$(if $(call glob-match,$1,*.*.new),\
$(info $1 : $(firstword $(call glob-match,$1,*.new)).extension $(word 3,$(call glob-match,$1,*.*)))\
$(call gen-rules,$(word 3,$(call glob-match,$1,*.*))),\
$(info $1 : $(patsubst %.new,%.extension,$1)))
$(foreach cmdline-target,$(filter %.new,$(MAKECMDGOALS)),$(call gen-rules,$(cmdline-target)))https://stackoverflow.com/questions/65349710
复制相似问题