我在 Makefile 中使用了一个带有 eval 的变量,它在项目的每个子目录中创建一个静态模式规则。但是我有两种方法可以处理它。
define STATIC_OBJ_RULE
$(OBJ_$(DIR)): $(OBJ_LOCAL_DIR)%.o: $(SRC_LOCAL_DIR)%.c $(DEP_LOCAL_DIR)%.dep
| $(OBJ_LOCAL_DIR) $(DEP_LOCAL_DIR)
$(COMPILE)
$(POSTCOMPILE)
$(RM) $$(word 2,$$^).tmp
$(TOUCH) $$@
endef
或者那样
define STATIC_OBJ_RULE
$(OBJ_$(DIR)): $(OBJ_LOCAL_DIR)%.o: $(SRC_LOCAL_DIR)%.c $(DEP_LOCAL_DIR)%.dep
| $(OBJ_LOCAL_DIR) $(DEP_LOCAL_DIR)
$$(COMPILE)
$$(POSTCOMPILE)
$(RM) $$(word 2,$$^).tmp
$(TOUCH) $$@
endef
(区别在于第三行,转义或不转义 COMPILE 和 POSTCOMPILE,它们生成目标文件和相应的依赖文件,并对依赖关系进行一些后处理)
对于第一种情况,每次运行目标文件的配方时,都会减少扩展,但我需要使用$
(其中的自动变量)转义其他变量(组成 COMPILE 和 POSTCOMPILE)
另一方面,由于make的目的是避免重新编译(当然是不必要的),这真的能实现什么吗?
那么,您是否认为一个是最佳实践而不是另一个?(或者我只是想太多了不值得的事情?
我很确定你必须用第二种方式来做:第一种方法是行不通的。
为什么? 因为如果你有一个扩展到编译行的变量COMPILE
,该变量的值必须包含自动变量,如$@
、$<
等,否则它就不能工作。 例如,它可能是这样的:
COMPILE = $(CXX) $(CPPFLAGS) $(CXXFLAGS) -o $@ -c $<
什么的。
如果您使用第一种方法,则在解析配方时将扩展COMPILE
变量,这意味着自动变量将展开,然后在运行规则时不会扩展,这意味着它们将为空,并且您的配方将不起作用。
一般来说,当像这样使用 define/eval 时,我更喜欢转义食谱的内容,这样 tose 食谱的所有工作方式都与 tose 食谱的工作方式相同,如果您直接不使用 define/eval 编写它们,它会起作用。