过滤 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
我需要在 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