问题
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
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
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.
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?
回答1:
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
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 $^ > $@
which is in turn expanded as (step-by-step):
step1:
norm.twolc: $(patsubst %,%.twolc,A B C)
cat $^ > $@
step2:
norm.twolc: A.twolc B.twolc C.twolc
cat $^ > $@
step3:
norm.twolc: A.twolc B.twolc C.twolc
cat 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.
来源:https://stackoverflow.com/questions/44669257/code-management-generate-source-files-with-slight-variations-of-various-rules