过滤Makefile列表中的相邻单词

过滤Makefile列表中的相邻单词,makefile,gnu-make,Makefile,Gnu Make,我需要在gnu makefile中操作一些C标志,我需要从标志中提取一些两个单词参数(例如,-mllvm,后面跟着空格,然后是一个子参数。我需要删除mllvm和后面的单词) 不幸的是,我没有看到一个直接的方法来做这件事。$(过滤器)不起作用,因为假定搜索参数是一个空格分隔的单词列表,并且模式是多个单词$(patsubst)似乎也不起作用,根据手册页,它: 在匹配模式的文本中查找空格分隔的单词 但我需要匹配多个单词,而不仅仅是单词。我想知道我是否遗漏了一些巧妙的技巧。我想你必须使用递归调用函数。也

我需要在gnu makefile中操作一些C标志,我需要从标志中提取一些两个单词参数(例如,
-mllvm
,后面跟着空格,然后是一个子参数。我需要删除
mllvm
和后面的单词)

不幸的是,我没有看到一个直接的方法来做这件事。
$(过滤器)
不起作用,因为假定搜索参数是一个空格分隔的单词列表,并且模式是多个单词
$(patsubst)
似乎也不起作用,根据手册页,它:

在匹配模式的文本中查找空格分隔的单词


但我需要匹配多个单词,而不仅仅是单词。我想知道我是否遗漏了一些巧妙的技巧。

我想你必须使用递归调用函数。也许是这样的:

removearg = $(if $2,$(if $(filter $1,$(word 1,$2)),$(call removearg,$1,$(wordlist 3,$(words $2),$2)),$(word 1,$2) $(call removearg,$1,$(wordlist 2,$(words $2),$2))))

keeparg = $(if $2,$(if $(filter $1,$(word 1,$2)),$(word 1,$2) $(word 2,$2) $(call keeparg,$1,$(wordlist 3,$(words $2),$2)),$(call keeparg,$1,$(wordlist 2,$(words $2),$2))))

CFLAGS := -DFOO -DBAR -mllvm llvmflag1 -mllvm llvmflag2

OTHER_CFLAGS := $(call removearg,-mllvm,$(CFLAGS))
MLLVM_FLAGS := $(call keeparg,-mllvm,$(CFLAGS))
基本上,removearg检查列表中的第一个单词是否等于第一个参数(
-mllvm
),如果是,则从第三个单词开始递归调用,跳过第一个和第二个单词;如果不是,则扩展到第一个单词,然后从第二个单词开始递归调用自己

keeparg函数是相同的,但如果
-mllvm
跳过下一个单词,则会扩展到前两个单词

埃塔

实际上,这里有一个更简单的方法:

removearg = $(filter-out $1^%,$(subst $1 ,$1^,$2))
keeparg = $(subst $1^,$1 ,$(filter $1^%,$(subst $1 ,$1^,$2)))

OTHER_CFLAGS := $(call removearg,-mllvm,$(CFLAGS))
MLLVM_FLAGS := $(call keeparg,-mllvm,$(CFLAGS))

这假设您在
CFLAGS
中永远不会有启动
-mllvm^
的选项。如果是这样,请选择除
^

之外的其他从未存在的字符(如果您想尝试帮助程序库,则碰巧有;)以编程方式解决任务的支持函数:

$(call while, $$(call glob-match,$(space)$$(CFLAGS),*-mllvm *),\
   tmp := $$(call glob-match,$(space)$$(CFLAGS),*-mllvm *)$(newline)\
   rest := $$(call spc-unmask,$$(word 3,$$(tmp)))$(newline)\
   llvm_flg := $$(firstword $$(rest))$(newline)\
   CFLAGS := $$(firstword $$(tmp)) $$(call tail,$$(rest))$(newline)\
   $$(info [[[$$(tmp) --- $$(rest) --- $$(CFLAGS) ]]])$(newline)\
   MLLVM_FLAGS+=$$(llvm_flg),\
MLLVM_FLAGS := $$(strip $$(MLLVM_FLAGS))$(newline)\
CFLAGS := $$(call spc-unmask,$$(CFLAGS))\
)
  • 条件:只要glob match在CFLAGS中返回一个-mllvm匹配。有一个小技巧可以避免在第一个*上出现空匹配:我们在字符串的开头插入$(空格)字符,这样匹配就永远不会为空
  • 正文(注意换行符的引用-这是$(eval)正确解释代码所必需的):
    • 将glob match的输出提取到临时变量中(在该输出中替换空格,请参见glob match)。输出是一个由三个元素组成的列表:从-mllvm开始的所有字符()、字符串-mllvm本身(注意末尾的空格)和它后面的所有字符()
    • 将第三个元素(CFLAGS的其余部分落后于第一个mllvm匹配项)转换回一个带空格的字符串,并将其放入rest
    • 将-mllvm标志(rest的第一个元素)的参数拉入llvm_flg
    • 修改CFLAGS以包含除-mllvm及其参数之外的所有内容
    • 打印变量作为调试辅助-当然要在生产中删除
    • 将新找到的-mllvm标志参数追加到输出变量
  • 退出声明:
    • 漂亮的打印MLLVM_标志
    • 从循环期间累积的CFLAG中删除空格替换字符
输出:

[[[ -DFOO§-DBAR§ -mllvm§ llvmflag1§-mllvm§llvmflag2 --- llvmflag1 -mllvm llvmflag2 --- -DFOO§-DBAR§ -mllvm llvmflag2 ]]]
[[[ -DFOO§-DBAR§§ -mllvm§ llvmflag2 --- llvmflag2 --- -DFOO§-DBAR§§  ]]]
CFLAGS = -DFOO -DBAR
MLLVM_FLAGS = llvmflag1 llvmflag2

我认为它也依赖于旗帜和它的论点之间的一个空格
$(strip)
预先设置它,以避免被过多的空格绊倒。我认为我可以安全地假设-mllvm和后续参数之间只存在一个空格(如果
其他
具有子字符串
-mllvm
的话,我可以添加一个断言以确定)。@Vroomfondel——只是查找strip,而且它明显地消除了单词之间的双空格。这真的很喜欢任何双间距问题。谢谢,这是一个很好的答案,但疯狂科学家的更简单。不幸的是,由于名誉的原因,我不能投票。
[[[ -DFOO§-DBAR§ -mllvm§ llvmflag1§-mllvm§llvmflag2 --- llvmflag1 -mllvm llvmflag2 --- -DFOO§-DBAR§ -mllvm llvmflag2 ]]]
[[[ -DFOO§-DBAR§§ -mllvm§ llvmflag2 --- llvmflag2 --- -DFOO§-DBAR§§  ]]]
CFLAGS = -DFOO -DBAR
MLLVM_FLAGS = llvmflag1 llvmflag2