首页
学习
活动
专区
圈层
工具
发布
社区首页 >问答首页 >Make/BASH/SH:死的简单前缀pop和字符串的后缀交换?

Make/BASH/SH:死的简单前缀pop和字符串的后缀交换?
EN

Stack Overflow用户
提问于 2020-12-17 23:17:32
回答 3查看 97关注 0票数 0

假设我对make做了一些非常规的使用。此外,假设我已经在这个用法中提出了一个名称方案,它对make以外的工具非常有用,并且几乎完全适合于make范例。

我几乎可以利用内置的make来完成这个任务,并且正在寻找一些魔法来使它在系统的语义和语法中“正常工作”。

现在,我有一个可构建的过程,具体如下:

代码语言:javascript
复制
# "<-" = "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

我要找的是一些神奇的东西:

代码语言:javascript
复制
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

我认为这可能是:

代码语言:javascript
复制
$(filter-out .c, $(patsubst %,%.c $(not-prefix $$*)))

如果没有-前缀存在,我想知道是否有一些内置的-或多或少地完成了这一任务?

或者,是否有一些真正的紧凑的巴什主义,可以做到这一点?

例如:

代码语言:javascript
复制
$(shell echo "$$*" | sed -E 's/[^.]*(.*)\.[^.]*$$/\1.new/' | grep -v -E '^\.new$$')

是超级多风和冗长,但也许有一些紧凑的方式来做到这一点?

到目前为止,我想出的最可读的是:

代码语言:javascript
复制
%.new: $$*.extension $(filter-out .new, $(shell echo "$$@" | cut -d '.' -f 1 --complement))

更新树构建递归问题的最小可验证示例:

代码语言:javascript
复制
%.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))
代码语言:javascript
复制
$ make descendant.ancestor.new

@: descendant.ancestor.new
<: descendant.ancestor.ext
^: descendant.ancestor.ext
ancestor.new
rm descendant.ancestor.ext

接下来,我将第二个"$“符号添加到规则中,以便在第二个展开期间执行它:

代码语言:javascript
复制
%.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))

产生的结果:

代码语言:javascript
复制
$ make descendant.ancestor.new
make: *** No rule to make target 'descendant.ancestor.new'.  Stop.

最后,我认为这应该是:

代码语言:javascript
复制
.SECONDEXPANSION:
 %.new: $$*.ext | $$(filter-out new, $$(shell echo "$$@" | cut -d '.' -f 1 --complement))

但是,相反,我所做的让它“只是起作用”是:

代码语言:javascript
复制
%.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:

这会产生比规则线更脆弱的行为:

代码语言:javascript
复制
$ 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
EN

回答 3

Stack Overflow用户

回答已采纳

发布于 2020-12-18 20:25:21

好的,谢谢你澄清你要找的东西。因此,我没有任何我会认为“非常简单”的东西,但是您可以完全使用GNU make使用以下方法:

代码语言:javascript
复制
e =
sp = $e $e
magic1 = $(if $(filter-out 1,$(words $(subst ., ,$1))),$1,)
magic = $(call magic1,$(subst $(sp),.,$(wordlist 2,1000,$(subst ., ,$1))))

现在,在任何您希望“魔术”发生的地方,调用magic函数:

代码语言:javascript
复制
.SECONDEXPANSION:
%.new: $$*.ext $$(call magic,$$@)

如果magic1宏的参数大于1 .,则扩展到它的参数,否则扩展到空字符串。magic宏去掉第一个“前缀”,并使用该值调用magic1

也许有更简单的方法来做到这一点,我并没有想出一个从我的头顶。

此外,我没有回顾你编辑的问题,所以我不确定你在那里添加的内容是否会在这里起作用。

票数 1
EN

Stack Overflow用户

发布于 2020-12-18 16:52:55

这里的问题是,大多数构建系统依赖于稳定的前缀和后缀,只有变化的茎(中间部分)。

在这里,您有一个任意变化的前缀,以及中间部分。因此,例如,在第一种依赖情况下,bar.biz.baz是所有名称中的公共词干。这是武断的。但是,所涉及的每个名称都有一个独立的任意前缀,如foo

为了避免与该工具发生冲突,我将尝试将foobiz.bar.baz以及其他每一对代码编码在一些变量中,这些变量充当了这些信息的主要来源。

样品制作。在这个解决方案中,我们只使用callfirstwordsecondword一个字符的substforeacheval

代码语言:javascript
复制
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)))))

输出:

代码语言:javascript
复制
$ 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

另一种方法,使用计算变量名。这里,除了模拟数据结构的计算变量之外,我们只使用foreachcalleval。除了嵌套变量展开之外,根本没有字符串处理:

代码语言:javascript
复制
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))))
票数 1
EN

Stack Overflow用户

发布于 2020-12-18 10:59:12

我要找的是一些神奇的东西: A.b -> ...c如果.= "“# so,它将去掉前缀(以点分隔),a#只在后缀以外的东西存在时才交换后缀。

我不完全理解您想要执行的操作,但是GNUmake表工具包有一些实用的字符串操作,尽管它的名称是:

代码语言:javascript
复制
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))"))

输出:

代码语言:javascript
复制
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 )

代码语言:javascript
复制
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)))
票数 0
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/65349710

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档