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
减少到
因此失败了。哎呀。
一个简单的变通方法,也是一个好的实践,就是使用$?'和‘$@'如果可能:
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=“$(标题)”
宏观扩张到:
但是克/小时
仍然是一个简单的词。(顺便提一下,这个成语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公司(请注意潜艇/目录甚至不存在,这只是意味着简化在检查文件之前发生。)