处理makefile中的依赖性中毒

时间:2011-11-15 17:32:10

标签: makefile dependencies

我正在努力重新编写最初设计的旧版本" (或不,视情况而定)是递归的。作为序言,有一天我们会转向更现代,富有表现力和更强大的东西(例如,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.soB的对象会将更改继承到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 ...)INCLUDESsimple返回$(origin ...);无论您使用file还是:=,都会发生这种情况。

简而言之,如果对范围变量使用+=,它只会使用作用于该目标的变量的定义;它没有看全局变量。如果您使用+=,它只使用全局变量。

1 个答案:

答案 0 :(得分:1)

如果您在文件名中删除了异常字符,则可以选择具有可变名称替换的特定于目标的变量:

A.so_CFLAGS = flags specific to building A.so
%.so %.o:
    @echo "${@}: ${CFLAGS} ${$@_CFLAGS} : ${filter %.o,${^}} ${filter %.c,${^}}"

这显然不会将当前构建的存档的名称传播到为该库构建的对象,但我不知道是否需要这样做。

这种方法有一些明显的缺陷,自然就像无法实际覆盖CFLAGS一样。但是,考虑到automake有同样的问题需要解决并采用愚蠢的文本替换,我想很多人都没有找到一个很好的解决方案。

作为旁注,您可以考虑使用automake而不是重新设计它。