我正在努力重新编写最初设计的旧版本" (或不,视情况而定)是递归的。作为序言,有一天我们会转向更现代,富有表现力和更强大的东西(例如,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的架构)。
简而言之,我想我的问题是:在makefile中防止依赖性中毒的理智/好方法是什么?是否有比我所概述的更好的策略?
修改的
如果有人试图按照上面所描述的范围变量的路径走下去,我会遇到一个起初并不完全明显的细微差别。
% : INCLUDES :=
# ...
SOMEVAR := /some/path
% : INCLUDES += -I${SOMEVAR}
...
SOMEVAR :=
使用:=
创建变量时,应立即评估:=
右侧的所有内容,而如果仅使用=
,则会延迟评估,直到目标配方评估{ {1}}。
但是,在评估目标配方时,INCLUDES
评估为空。如果将定义更改为:
SOMEVAR
...然后它会立即强制% : INCLUDES := whatever
# ...
SOMEVAR := /some/path
% : INCLUDES := ${INCLUDES} -I${SOMEVAR}
...
SOMEVAR :=
进行评估,而不是推迟评估,但SOMEVAR
不会评估其先前的作用域定义,而是评估全局定义。
INCLUDES
说$(flavor ...)
是INCLUDES
,simple
返回$(origin ...)
;无论您使用file
还是:=
,都会发生这种情况。
简而言之,如果对范围变量使用+=
,它只会使用作用于该目标的变量的定义;它没有看全局变量。如果您使用+=
,它只使用全局变量。
答案 0 :(得分:1)
如果您在文件名中删除了异常字符,则可以选择具有可变名称替换的特定于目标的变量:
A.so_CFLAGS = flags specific to building A.so
%.so %.o:
@echo "${@}: ${CFLAGS} ${$@_CFLAGS} : ${filter %.o,${^}} ${filter %.c,${^}}"
这显然不会将当前构建的存档的名称传播到为该库构建的对象,但我不知道是否需要这样做。
这种方法有一些明显的缺陷,自然就像无法实际覆盖CFLAGS
一样。但是,考虑到automake
有同样的问题需要解决并采用愚蠢的文本替换,我想很多人都没有找到一个很好的解决方案。
作为旁注,您可以考虑使用automake
而不是重新设计它。