GNU make中圆括号和大括号的区别

2020-06-01 23:28:41

写一本关于GNU make的书的一个问题/好处是人们会问我很多问题。今天早上有人对我说:尤其是大括号和圆括号总是让我迷惑不解。一如既往,GNU Make Questions的第一个停靠港应该是FSF';的手册。它说明如下:";要替换变量值,请在圆括号或大括号中写入一个美元符号,后跟变量名称:$(Foo)或${foo}是对变量foo的有效引用。";

您可以看到简单的变量引用是有效的,就像使用替换引用的替换(我将World更改为每个人)一样。

但是快速搜索GNU make手册就会发现,在谈论函数调用时再次提到花括号:";用于括起函数调用的分隔符,无论是圆括号还是花括号,只能出现在匹配对的参数中;另一种分隔符可能单独出现。如果参数本身包含其他函数调用或变量引用,最明智的做法是对所有引用使用相同类型的分隔符;编写$(subst,a,b,$(X)),而不是$(subst,a,b,${x})。这是因为它更清晰,而且只匹配一种类型的分隔符来查找引用的末尾。";

该描述的唯一问题是使用$(Subst)给出的示例工作得很好。以下是圆括号和大括号的四种可能组合:

这样做效果很好。如果您需要使用文字圆括号或大括号,那么不同的形式可能会很有帮助。假设您要将EVERY)更改为(,或将}更改为{。这是一个包含两个表情符号的Makefile,我们使用替换将)翻转为(和}翻转为{:

等等!这并没有百分之百奏效。前两个$(Info)调用确实很好地输出了$(Smile)和$(curly-smile)的值。然后,$(info$(curly-smile:}={))将}更改为{,没有问题,因为替换是使用圆括号进行的(参见$(curly-smile:)的开头)。

但是,$(info$(smile:)=())发生了什么情况,为什么输出是=()?嗯,GNU make将$(smile:)解释为一个变量引用,名为smile:,而不是smile!您可以通过定义一个名为SMILE:的变量来验证这一点,使用这个技巧(您必须这样做才能创建一个名为SMILE:的变量,因为如果您尝试SMILE::=foo,GNU make会认为您正在制定一条规则来创建一个名为SMILE的文件!)。

但是在上面的Makefile中,smile:isn没有定义,所以它的计算结果为空字符串,我们剩下的是$(info$(smile:)=())的其余部分,即=(),GNU将输出作为字符串文字。这里发生的事情是GNU make将$(smile:)末尾的)视为结束$(smile:),而不是字面上的)。

如果您想要处理GNU make视为特殊的字符,最好定义变量来代替它们。由于GNU make将在替换变量之前解析函数调用、变量引用等,因此您将获得预期的输出。

输出的第一行很容易理解。这与$(smile:)出现的问题相同,但是${curly-smile:}被解释为引用一个不存在的名为curly-smile:的变量。但是最后一行呢?

GNU make再次感到困惑,将$(info${smile:)=(})解析为$(info${smile:),(因为)终止了$(Info)),然后是=(})。

这个故事的寓意是..。不要在GNU make中混合使用圆括号和大括号,如果您需要将它们作为文字使用,那么定义包含它们的变量并使用变量引用。