如何在makefile中不使用空格将字符串跨越多行?

23
在makefile中,使用\转义换行符可以将单行长字符串内容拆分为多个源行。然而,换行符会被替换为空格。是否存在一个透明的源代码换行符不影响字符串内容?
VAR=w\
o\
r\
d

all:
    echo $(VAR)

期望输出为'word',但实际输出为'w o r d'。


2个回答

19

最简单的解决方案是使用$\<newline>来拆分行(至少在使用GNU Make时是这样):

VAR = w$\
      o$\
      r$\
      d

all:
    echo $(VAR)
输出将会是"word",没有空格。这是因为GNU Make会用一个空格替换反斜杠-换行符-空格,使得对VAR的赋值与以下等价:
VAR = w$ o$ r$ d

https://www.gnu.org/software/make/manual/html_node/Reference.html#Reference得知: “在美元符号后跟着除美元符号、左圆括号或左花括号之外的字符会将该单个字符视为变量名称。”因此,$<space>对是对名为单个空格字符的变量进行扩展。由于默认情况下未定义此变量,因此它将扩展为空字符串。

请注意,变量VAR仍将包含$<space>对,直到扩展为止。大多数情况下,这并不重要,但如果您的makefile依赖于使用$(value VAR)来处理基础(未扩展)值,则上述技术可能会提供意想不到的结果。

另外,最近发布的GNU Make 4.3现在明确记录了这种分割行的技巧(https://www.gnu.org/software/make/manual/make.html#Splitting-Lines):

在不添加空格的情况下拆分

如果您需要拆分一行但不想添加任何空格,则可以利用一个微妙的技巧:将反斜杠/换行对替换为三个字符“美元符号/反斜杠/换行”:

var := one$\
       word

在make命令去除反斜杠/换行并将下一行压缩成单个空格后,这相当于:

var := one$ word

然后make将执行变量扩展。变量引用'$'代表一个名字为“”(空格)的一字符变量,但是该变量不存在,因此扩展为一个空字符串,最终赋值相当于:

var := oneword
对于其他想法,请参见我在类似问题上的答案: 如何在没有空格的情况下在Makefile中将变量定义跨越多行? 关于行延续选项的更长讨论可在我的文章“GNU Make行延续”中找到: http://drmikehenry.com/gnu-make-line-continuations/

1
这里有一些技巧,它们依赖于当前未定义的行为。例如,现在直接创建一个包含空格的变量名是不合法的(可以使用技巧来实现),因此尝试扩展包含空格的变量名可能会变得非法。此外,它依赖于反斜杠在$ \对中被解释为$之前。我知道Michael已经在Savannah上提交了一个错误报告,要求定义和支持这种行为。 - MadScientist
总是很高兴听到一个积极的维护者!(http://mad-scientist.net/about/)这个请求(https://savannah.gnu.org/bugs/index.php?54116)的动机是,文档(但不包括实现)目前禁止在变量名称中使用空格。通过对其进行文档化,很少有机会获得可用的新功能,可以追溯地应用于(所有?)以前的版本。我希望 GNU Make 维护者能够将其记录为官方功能,消除可读性较高的 Makefile 中的障碍之一。 - Michael Henry
将这个答案(例如关于“value”的有用信息,有时可以用“:=”避免)分成两个问题看起来很奇怪。我们应该将这一个标记为重复吗? - Davis Herring
变量名中的空格在实现中是不允许的,如果直接这样做:foo bar = biz 将会出错。但是你仍然可以通过间接方式来实现:如果 $s 扩展为一个空格,那么 foo$sbar = biz 将设置名为 foo bar 的变量。之所以禁止使用空格,是因为我们希望有自由地编写像 $(foo bar) 这样的内容,并且它们与引用名为 foo bar 的变量的含义不同。单个空格可以被特殊处理。它确实很好,可以在所有版本的 GNU make 中工作。但你必须承认,它感觉有点像一个 hack :). - MadScientist
它能够工作的原因确实是一个hack;但是语法本身在我看来相当不错:\插入一个空格,$\则不会。我见过将$(foo bar)解释为$(call foo,bar)的想法。消除call只是一个小小的好处,比起拥有一种执行可读函数缩进的方法来说,这个好处要小得多,在我看来。此外,向后兼容性对我来说是必须具备的功能;我们几乎不能要求使用Make 3.81(现在已经12年了)。在我能够使用像$(foo bar)这样的假设新功能之前,还需要十年时间 :-) - Michael Henry

10

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接