12.18.4自动规则重写

一些制作实施,如Solaris和Tru64,在中搜索前提条件VPATH公司然后将每个出现的内容重写为规则中的普通单词。例如:

#这对GNU来说是不可移植的。VPATH=/包装/规格f.c:如果.ccp如果.c f.c

执行cp/pkg/src/if.c f.c如果如果.c在中找到../pkg/src.

然而,这一规则在实践中导致了实际问题。例如,如果源目录包含一个名为测试那就是在依赖项Solaris中使用制作重写命令,如如果测试-r foo…'至'如果/pkg/src/test-r foo;',这通常是不可取的。事实上,制作完全不知道规则中使用的shell语法,因此VPATH重写可能适用于任何空白分隔词在规则中,包括shell变量、函数和关键字。

$mkdir生成$cd内部版本$cat>生成文件<<'END'VPATH=。。all:arg函数用于echofunc(){用于“$$@”中的arg;执行echo$$arg;done;}\func“你好世界”结束$触摸/参数/功能/用于/回声$制作../func(){../用于“$@”中的../arg;do../echo$arg;done;}\../func“你好,世界”sh:第1行出现语法错误:意外的“do”***错误代码2

为了避免这个问题,可移植的makefile不应该提及源代码名称为shell关键字的文件或依赖项,如对于直到,一个shell命令,如海湾合作委员会测试,或对应的中使用的shell函数或变量生成文件配方。

由于这些问题,GNU制作和许多其他制作实现不会重写命令,因此可移植的makefile应该搜索VPATH公司手动操作。写这句话很诱人:

#这对于Solaris厂商来说是不可移植的。VPATH=/包装/规格f.c:如果.ccp`test-f if.c||echo$(VPATH)/`if.c f.c

然而,“先决条件重写”在这里仍然适用。所以如果如果.c在中../pkg/src、Solaris和Tru64制作执行

cp`test-f/pkg/src/if.c||echo/pkg/src/`如果.c f.c

减少到

cp如果.c f.c

因此失败了。哎呀。

一个简单的变通方法,也是一个好的实践,就是使用$?'和$@'如果可能:

VPATH=/包装/规格f.c:如果.ccp$$@

但这并不能很好地推广到具有多个前提条件。更通用的解决方法是重写规则,以便先决条件如果.c从来都不是一个简单的单词。对于例如,假设这三条规则是安全的如果.c在中../pkg/src其他文件位于工作目录中:

VPATH=/包装/规格f.c:如果.c f1.ccat `测试-f/if.c||echo$(VPATH)/`if.c f1.c>$@g.c:如果.c g1.ccat“test-f”if.c“||echo$(VPATH)/`if.c g1.c>$@h.c:如果.c h1.ccat`test-f“if.c”||echo$(VPATH)/`if.c h1.c>$@

当你的先决条件在宏中时,情况会变得更糟。

VPATH=/包装/规格集管=f.h g.h h.h安装页眉:$(页眉)i单位为$(标题);做\$(安装)-m 644\`test-f$$i||echo$(VPATH)/`$$i\$(DESTDIR)$(含)/$$i\完成

以上内容安装HEADERS这条规则不能抵御太阳光,因为对于i单位为美元(标题);扩展到f.h g.h h.h中的i;哪里f.h(飞行高度)克/小时是普通的词,因此从属于VPATH公司调整。

如果这三个文件在../pkg/src,规则的运行方式为:

对于我来说/pkg/src/f.h/pkg/src/g.h h.h;做\安装-m 644\`测试-f$i||echo/包装/src/`$i\/usr/local/include/$i\完成

两个人先在哪里安装调用失败。例如,考虑一下f.h(飞行高度)安装:

安装-m 644\`测试-f/pkg/src/f.h||\回声/包装/规格/\`../pkg/src/f.h\/usr/local/include//pkg/src/f.h;

它简化为:

安装-m 644\../pkg/src/f.h\/usr/local/include//pkg/src/f.h;

请注意,手册虚拟路径搜索没有在这里造成任何问题;但是,此命令将安装离岸价格在不正确的目录中。

尝试引用$(标题)在某种程度上,就像我们所做的那样食品。c(c)几个makefile之前没有帮助:

安装页眉:$(页眉)headers=“$(headers)”\$$headers中的for i;做\$(安装)-m 644\`test-f$$i||echo$(VPATH)/`$$i\$(DESTDIR)$(含)/$$i\完成

现在,headers=“$(标题)”宏观扩张到:

标题='.h.g.h.h'

但是克/小时仍然是一个简单的词。(顺便提一下,这个成语headers=“$(headers)”;$$headers中的for i;是个好东西想法如果$(标题)可以为空,因为某些外壳诊断上的语法错误对于i in;.)

一个解决方法是去除不需要的../pkg/src/手动添加前缀:

VPATH=/包装/规格集管=f.h g.h h.h安装页眉:$(页眉)headers=“$(headers)”\$$headers中的for i;做\i=`expr“$$i”:'$(VPATH)/\(.*\)'`;$(安装)-m 644\`test-f$$i||echo$(VPATH)/`$$i\$(DESTDIR)$(包括ir)/$$i\完成

Automake也有类似的功能。然而,只有在以下情况下,上述黑客才能工作中列出的文件标题位于当前目录中或子目录;它们不应该位于封闭目录中。如果我们有标题=/f.h(飞行高度),上述片段将在VPATH中失败使用Tru64构建制作原因是不仅如此Tru64系列制作重写依赖项,但它也简化了他们。因此../小时成为../pkg/f.h而不是../pkg/src//f.h(飞行高度)这显然挫败了任何脱衣的企图领先者../pkg/src/组件。

以下示例使Tru64的行为制作更明显。

$cat生成文件VPATH=子全部:/foo公司回声/foo公司$最小二乘法生成文件foo$制作回波foofoo公司

附属国../foo在中找到子//foo公司,但Tru64制作将其简化为foo公司(请注意潜艇/目录甚至不存在,这只是意味着简化在检查文件之前发生。)