问题描述
我有一个声明性语言的源文件(实际上是twolc
),我需要写很多变种:规范版本和许多非规范版本,每个版本都有一个或多个不同于规范的版本.例如,说规范文件具有三个规则:
I have a source file in a declarative language (twolc
, actually) that I need to write many variations on: a normative version and many non-normative versions, each with one or more variations from the norm. For example, say the normative file has three rules:
Rule A:
Do something A-ish
Rule B:
Do something B-ish
Rule C:
Do something C-ish
那么一个变体可能具有与A
和C
的规范完全相同的规则,但是对于B
的规则却不同,我将其称为B-1
:
Then one variation might have the exact same rules as the norm for A
and C
, but a different rule for B
, which I will call 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多个文件需要手工编辑完全相同的规则.
Imagine that you have many different subtle variations on many different rules, and you have my situation. The problem I am worried about is code maintainability. If, later on, I decide that Rule A
needs to be refactored somehow, then I will have 50+ files that need to have the exact same rule edited by hand.
我的想法是为每个规则使用单独的文件,并使用cat
:cat A.twolc B.twolc C.twolc > norm.twolc
,cat A.twolc B-1.twolc C.twolc > not-norm.twolc
等将它们连接为变体.
My idea is to have separate files for each rule and concatenate them into variations using cat
: cat A.twolc B.twolc C.twolc > norm.twolc
, cat A.twolc B-1.twolc C.twolc > not-norm.twolc
, etc.
是否有设计用于解决此类问题的工具?有没有比我想到的方法更好的方法?我提出的解决方案是否有我应该注意的弱点?
Are there any tools designed to manage this kind of problem? Is there a better approach than the one I have in mind? Does my proposed solution have weaknesses I should watch out for?
推荐答案
添加了makefile标记后,这是基于GNU-make的(仅Gnu make)解决方案:
As you added the makefile tag, here is a GNU-make-based (and Gnu make only) solution:
# 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
.然后,将每个扩展结果实例化(eval
)作为正常的生成规则.例如:对于v=norm
,GEN_rules
扩展产生:
patsubst
is straightforward. The foreach-eval-call
is a bit more tricky. Long story short: it loops over all variations (foreach
). For each variation v
, it expands (call
) GEN_rules
by replacing $(1)
by $(v)
(the current variation) and $$
by $
. Each expansion result is then instantiated (eval
) as a normal make rule. Example: for v=norm
, the GEN_rules
expansion produces:
norm.twolc: $(patsubst %,%.twolc,$(norm-rules))
cat $^ > $@
依次扩展为(逐步):
第1步:
norm.twolc: $(patsubst %,%.twolc,A B C)
cat $^ > $@
第二步:
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
更新,则执行配方.
which does what you want: if norm.twolc
does not exist or if any of A.twolc
, B.twolc
, C.twolc
is more recent than norm.twolc
, the recipe is executed.
这篇关于代码管理:生成带有各种规则的细微变化的源文件的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持!