代码管理:生成具有各种规则细微变化的源文件
code management: generate source files with slight variations of various rules
我有一个声明性语言的源文件(twolc
,实际上)我需要写很多变体:一个规范版本和许多非规范版本,每个版本都有一个或多个变体规范。例如,假设规范文件具有三个规则:
Rule A:
Do something A-ish
Rule B:
Do something B-ish
Rule C:
Do something C-ish
那么一个变体可能与 A
和 C
的规范具有完全相同的规则,但 B
的规则不同,我将其称为 B-1
:
Rule A:
Do something A-ish
Rule B-1:
Do something B-ish, but with a flourish
Rule C:
Do something C-ish
假设您对许多不同的规则有许多不同的细微变化,并且您有我的情况。我担心的问题是代码的可维护性。如果稍后我决定 Rule A
需要以某种方式重构,那么我将有 50 多个文件需要手动编辑完全相同的规则。
我的想法是为每个规则创建单独的文件,并使用 cat
将它们连接成变体:cat A.twolc B.twolc C.twolc > norm.twolc
、cat A.twolc B-1.twolc C.twolc > not-norm.twolc
等
是否有专为解决此类问题而设计的工具?有没有比我想到的更好的方法?我提出的解决方案是否有我应该注意的弱点?
当您添加 makefile 标签时,这里是一个基于 GNU-make(且仅 Gnu make)的解决方案:
# Edit this
RULES := A B B-1 C
VARIATIONS := norm not-norm
norm-rules := A B C
not-norm-rules := A B-1 C
# Do not edit below this line
VARIATIONSTWOLC := $(patsubst %,%.twolc,$(VARIATIONS))
all: $(VARIATIONSTWOLC)
define GEN_rules
$(1).twolc: $$(patsubst %,%.twolc,$$($(1)-rules))
cat $$^ > $$@
endef
$(foreach v,$(VARIATIONS),$(eval $(call GEN_rules,$(v))))
clean:
rm -f $(VARIATIONSTWOLC)
patsubst
很简单。 foreach-eval-call
有点棘手。长话短说:它遍历所有变体 (foreach
)。对于每个变体 v
,它通过将 $(1)
替换为 $(v)
(当前变体)并将 $$
替换为 [= 来扩展 (call
) GEN_rules
24=]。然后将每个扩展结果实例化 (eval
) 作为正常的 make 规则。示例:对于 v=norm
,GEN_rules
扩展产生:
norm.twolc: $(patsubst %,%.twolc,$(norm-rules))
cat $^ > $@
依次展开为(逐步):
第一步:
norm.twolc: $(patsubst %,%.twolc,A B C)
cat $^ > $@
第 2 步:
norm.twolc: A.twolc B.twolc C.twolc
cat $^ > $@
第 3 步:
norm.twolc: A.twolc B.twolc C.twolc
cat A.twolc B.twolc C.twolc > norm.twolc
做你想做的事:如果 norm.twolc
不存在或者 A.twolc
、B.twolc
、C.twolc
中的任何一个比 norm.twolc
更新, 配方被执行。
我有一个声明性语言的源文件(twolc
,实际上)我需要写很多变体:一个规范版本和许多非规范版本,每个版本都有一个或多个变体规范。例如,假设规范文件具有三个规则:
Rule A:
Do something A-ish
Rule B:
Do something B-ish
Rule C:
Do something C-ish
那么一个变体可能与 A
和 C
的规范具有完全相同的规则,但 B
的规则不同,我将其称为 B-1
:
Rule A:
Do something A-ish
Rule B-1:
Do something B-ish, but with a flourish
Rule C:
Do something C-ish
假设您对许多不同的规则有许多不同的细微变化,并且您有我的情况。我担心的问题是代码的可维护性。如果稍后我决定 Rule A
需要以某种方式重构,那么我将有 50 多个文件需要手动编辑完全相同的规则。
我的想法是为每个规则创建单独的文件,并使用 cat
将它们连接成变体:cat A.twolc B.twolc C.twolc > norm.twolc
、cat A.twolc B-1.twolc C.twolc > not-norm.twolc
等
是否有专为解决此类问题而设计的工具?有没有比我想到的更好的方法?我提出的解决方案是否有我应该注意的弱点?
当您添加 makefile 标签时,这里是一个基于 GNU-make(且仅 Gnu make)的解决方案:
# Edit this
RULES := A B B-1 C
VARIATIONS := norm not-norm
norm-rules := A B C
not-norm-rules := A B-1 C
# Do not edit below this line
VARIATIONSTWOLC := $(patsubst %,%.twolc,$(VARIATIONS))
all: $(VARIATIONSTWOLC)
define GEN_rules
$(1).twolc: $$(patsubst %,%.twolc,$$($(1)-rules))
cat $$^ > $$@
endef
$(foreach v,$(VARIATIONS),$(eval $(call GEN_rules,$(v))))
clean:
rm -f $(VARIATIONSTWOLC)
patsubst
很简单。 foreach-eval-call
有点棘手。长话短说:它遍历所有变体 (foreach
)。对于每个变体 v
,它通过将 $(1)
替换为 $(v)
(当前变体)并将 $$
替换为 [= 来扩展 (call
) GEN_rules
24=]。然后将每个扩展结果实例化 (eval
) 作为正常的 make 规则。示例:对于 v=norm
,GEN_rules
扩展产生:
norm.twolc: $(patsubst %,%.twolc,$(norm-rules))
cat $^ > $@
依次展开为(逐步):
第一步:
norm.twolc: $(patsubst %,%.twolc,A B C)
cat $^ > $@
第 2 步:
norm.twolc: A.twolc B.twolc C.twolc
cat $^ > $@
第 3 步:
norm.twolc: A.twolc B.twolc C.twolc
cat A.twolc B.twolc C.twolc > norm.twolc
做你想做的事:如果 norm.twolc
不存在或者 A.twolc
、B.twolc
、C.twolc
中的任何一个比 norm.twolc
更新, 配方被执行。