【发布时间】:2011-12-03 04:16:50
【问题描述】:
我正在重写一个最初“设计”(或不是,视情况而定)为递归的旧版本。作为序言,总有一天我们会转向更现代、更有表现力和更强大的东西(例如,scons)。然而,那一天不是现在。
作为这项工作的一部分,我正在将应该是通用变量/宏和目标/配方的内容整合到一些简洁的规则文件中,这些规则文件将作为主要构建的一部分包含在内。构建的每个子部分都将使用一个小的 makefile 来添加目标和依赖项,而在这些子 makefile 中添加的变量很少。顶级的 makefile 将包含所有的 makefile,允许所有内容都对依赖树做出贡献。
我必须承认,我完全不相信人们会在修改 makefile 时使用良好的判断力。作为我担心的一个例子:
CFLAGS = initial cflags
all: A.so
%.so %.o:
@echo "${@}: ${CFLAGS} : ${filter 5.o,${^}} ${filter %.c,${^}"
%.c :
true
%.o : %.c
A.so : B.so a1.o a2.o a3.o
B.so : b1.o b2.o b3.o
A.so : CFLAGS += flags specific to building A.so
如果我没有搞砸复制那个例子,情况是这样的:A.so 将链接到B.so,而A.so 的对象需要构建特殊标志;但是,B.so 和 B 的对象将继承对 CFLAGS 的更改。
我宁愿有一个单一的目标来构建大多数(如果不是全部)目标文件,甚至可以专门为那些需要稍微不同标志的那些对象修改 CFLAGS,以促进对更通用目标的重用(如果只需要担心一个目标/配方,则调试会更容易)。
在我完成重新构建这个构建之后,我完全不相信有人不会做这种愚蠢的事情;更糟糕的是,如果我不在身边审核,它可能会通过同行评审。
我一直在考虑做这样的事情:
% : CFLAGS = initial cflags
... 这将防止依赖中毒,除非有人随后更新它:
% : CFLAGS += some naive attempt at altering CFLAGS for a specific purpose
但是,如果只有 1000 个目标(非常保守的估计),并且分配给变量的内存大约为 1k,那么我们将增加大约 1mb 的开销,这可能会显着影响查找 CFLAGS 值所需的时间通过配方工作(当然取决于 gmake 的架构)。
简而言之,我想我的问题是:在生成文件中防止依赖中毒的理智/好方法是什么?有比我概述的更好的策略吗?
编辑
如果有人尝试按照上述范围变量的路径进行研究,我会遇到一开始并不完全明显的细微差别。
% : INCLUDES :=
# ...
SOMEVAR := /some/path
% : INCLUDES += -I${SOMEVAR}
...
SOMEVAR :=
当使用:= 创建变量时,应立即评估:= 右侧的所有内容,而如果仅使用=,则会延迟评估,直到目标配方评估INCLUDES。
但是,当评估目标配方时,SOMEVAR 的评估结果为空。如果您将定义更改为:
% : INCLUDES := whatever
# ...
SOMEVAR := /some/path
% : INCLUDES := ${INCLUDES} -I${SOMEVAR}
...
SOMEVAR :=
...然后它会强制立即评估 SOMEVAR 而不是延迟评估,但 INCLUDES 不会评估其先前范围的定义,而是评估全局定义。
$(flavor ...) 表示INCLUDES 是simple,而$(origin ...) 返回file;无论您使用:= 还是+=,都会出现这种情况。
简而言之,如果您在作用域变量上使用+=,它只会使用作用域为该目标的变量的定义;它不看全局变量。如果你使用:=,它只使用全局变量。
【问题讨论】:
标签: makefile dependencies