过滤 Makefile 列表中的相邻单词

Filtering adjacent words in Makefile list

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

CFLAGS := -DFOO -DBAR -mllvm llvmflag1 -mllvm llvmflag2
OTHER_CFLAGS := ??   #should be -DFOO -DBAR
MLLVM_FLAGS  := ??   #should be -mllvm llvmflag1 -mllvm llvmflag2

不幸的是,我没有看到执行此操作的直接方法。 $(filter) 不起作用,因为搜索参数假定为 space 分隔的单词列表,并且模式是多个单词。 $(patsubst) 似乎也不起作用,根据手册页,它:

Finds whitespace-separated words in text that match pattern...

但我需要匹配多个单词,而不仅仅是单词。我想知道是否有任何我可能遗漏的巧妙技巧。

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

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

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

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 ^%,$(subst  ,^,))
keeparg = $(subst ^, ,$(filter ^%,$(subst  ,^,)))

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

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

之外的其他不存在的字符

如果您想尝试帮助程序库,gmtt 碰巧有 ;) 以编程方式解决您的任务的支持函数:

$(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 returns匹配CFLAGS中的-mllvm。有一个小技巧可以避免第一个 * 出现空匹配:我们在字符串的开头偷偷加入一个 $(space) 字符,这样匹配就永远不会为空。
  • 正文(注意换行符的引用 - 这是 $(eval) 正确解释代码所必需的):
    • 将 glob-match 的输出提取到一个临时变量中(spaces 在此输出中被替换,请参阅 glob-match)。输出是一个包含三个元素的列表:直到 -mllvm 的所有字符 ()、字符串 -mllvm 本身(注意末尾的 space)和所有字符 ()关注它。
    • 将第三个元素(第一个 -mllvm 匹配项后面的其余 CFLAGS)转换回具有 spaces 的字符串并将其放入 rest
    • 将 -mllvm 标志的参数(这是 rest 的第一个元素)提取到 llvm_flg
    • 修改 CFLAGS 以包含除 -mllvm 及其参数之外的所有内容
    • 打印变量作为调试辅助 - 当然在生产中删除它
    • 将新找到的 -mllvm 标志参数附加到输出变量
  • 退出语句:
    • 漂亮的印花MLLVM_FLAGS
    • 从循环过程中累积的 CFLAGS 中删除 space 个替换字符

输出:

[[[ -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