Makefile简化:如何减少$(basename $@)重复使用并泛化规则?
具体简化思路
- 替换冗余的
$(basename $@)写法:Make内置自动变量$*代表模式规则中%匹配到的文本段,语义清晰,完全可以替代反复写的后缀剥离逻辑,不需要手动调用basename做字符串处理。比如目标是FirstSpec.run时,匹配%.run规则的%段是FirstSpec,$*取值就是FirstSpec,比$(basename $@)更简洁且无额外字符串计算开销。 - 合并重复的零散编译规则:你现在单独编写的
first.compile、follow.compile、Spec.compile、GrammarUtil.compile规则核心逻辑完全一致——都是编译和目标名同名的.scala文件,这类重复逻辑不需要每个目标单独写一行,只要一条静态模式规则就能覆盖所有同类目标。 - 泛化带共同依赖的Spec目标:
FirstSpec.compile、FollowSpec.compile的依赖结构完全一致,不需要每个目标单独罗列完整依赖链,只需要把公共依赖统一挂载到对应目标上即可,彻底去掉重复的编译命令行。 - 把硬编码的清理文件项抽到独立变量管理,后续新增生成文件时不需要反复修改clean规则。
简化后的Makefile参考
SPECS=First Follow EXAMPLES_PATH=../.. ROOT_PATH=../${EXAMPLES_PATH} SCALAV=2.12 APSLIB=${ROOT_PATH}/lib/aps-library-${SCALAV}.jar SCALA_FLAGS=.:${APSLIB} APS2SCALA=${ROOT_PATH}/bin/aps2scala # 统一管理所有需要编译的目标 COMPILE_TARGETS = GrammarUtil first follow Spec FirstSpec FollowSpec # 统一管理生成的scala源文件,避免clean规则硬编码 GENERATED_SCALA = grammar.scala first.scala follow.scala all: $(addsuffix Spec.compile, $(SPECS)) $(addsuffix Spec.run, $(SPECS)) # 通用APS文件生成scala规则 %.generate: ${APS2SCALA} -DCOT -p ${EXAMPLES_PATH}:${ROOT_PATH}/base $* # 通用scala程序运行规则 %.run: @scala -cp ${SCALA_FLAGS} $* # 通用编译规则:一次性覆盖所有单scala文件编译场景,替代原来零散编写的多段重复.compile规则 # 规则逻辑:所有编译目标都依赖与目标同名的.scala源文件 $(addsuffix .compile, $(COMPILE_TARGETS)): %.compile: %.scala scalac -cp ${SCALA_FLAGS} $< # 统一给所有Spec目标挂载公共依赖,无需每个目标单独写完整依赖链 FirstSpec.compile FollowSpec.compile: Spec.compile grammar.generate GrammarUtil.compile # 给生成源文件对应的编译目标补生成依赖 GrammarUtil.compile: grammar.generate first.compile: first.generate follow.compile: follow.generate clean: rm -f *.class $(GENERATED_SCALA)
额外优化提示
- 原代码中
FirstSpec.compile、FollowSpec.compile的规则块内重复编写了和通用规则完全一致的scalac命令,优化后这部分冗余代码完全删除,只保留差异化的依赖挂载即可。 - 尽量优先使用Make内置的模式匹配、自动变量逻辑,减少手动字符串处理(比如反复调用basename剥后缀),这类写法既冗余又容易因为路径带后缀的特殊场景出现取值错误。
内容的提问来源于stack exchange,提问作者Node.JS
相关产品推荐
相关产品推荐

