如何在没有空格的Makefile中跨多行分解变量定义



考虑以下Makefile

CP = .:${HADOOP_HOME}/share/hadoop/common/lib/hadoop-auth-2.2.0.jar:
${HADOOP_HOME}/share/hadoop/hdfs/hadoop-hdfs-2.2.0.jar:
${HADOOP_HOME}/share/hadoop/common/hadoop-common-2.2.0.jar:
${HADOOP_HOME}/share/hadoop/mapreduce/hadoop-mapreduce-client-core-2.2.0.jar:
${HADOOP_HOME}/share/hadoop/mapreduce/lib/hadoop-annotations-2.2.0.jar
all:
echo $(CP)

运行make的输出为

.:/home/hduser/Hadoop/hadoop-2.2.0/share/hadoop/common/lib/hadoop-auth-2.2.0.jar: /home/hduser/Hadoop/hadoop-2.2.0/share/hadoop/hdfs/hadoop-hdfs-2.2.0.jar: /home/hduser/Hadoop/hadoop-2.2.0/share/hadoop/common/hadoop-common-2.2.0.jar: /home/hduser/Hadoop/hadoop-2.2.0/share/hadoop/mapreduce/hadoop-mapreduce-client-core-2.2.0.jar: /home/hduser/Hadoop/hadoop-2.2.0/share/hadoop/mapreduce/lib/hadoop-annotations-2.2.0.jar

注意每个:后面都有空格。

有没有一种方法可以用换行符来定义变量CP,但不需要用多余的空格来替换每一行换行符?

不可能阻止反斜杠换行成为空格,而且之后尝试删除空格是很笨拙和容易出错的(如果应该有空格怎么办?),但您可以在生成空格时删除每个空格。这具有在任何地方工作的显著优势,即使在函数调用内部也是如此。诀窍是将生成的空间嵌入到一个扩展为零的表达式中。

带有空/未定义foo$(call foo)可以工作,但我们可以做得更好:变量名可以在(GNU)Make中包含空格。分配给他们很难,但我们无论如何都不想。因此,我们可以将其缩短为$(a b)甚至$(a );在查找之前,反斜杠换行符将变成一个空格。但即使是一个空间也能工作:

foo=bar$(
)baz

最后,对于单字符变量名,可以省略括号:

foo=bar$
baz

…最后看起来我们(完全)在转义换行符,而不是以某种方式使用它。只要没有分配给" "(这比使用更疯狂!)。

最简单的解决方案是使用$<newline>来拆分行。使用为简洁起见,请使用以下伪路径:

CP = one$
two$
three$
four
all:
echo $(CP)

输出将是"onetwothree4",没有空格。这是因为GNU Make将用单个空格替换反斜杠换行空白,使分配给CP相当于:

CP = one$ two$ three$ four

发件人https://www.gnu.org/software/make/manual/html_node/Reference.html#Reference:"A美元符号后面跟美元符号以外的字符,左括号或大括号将该单个字符视为变量名。"因此,$<space>对是名称为单个的变量的展开式空间字符。由于默认情况下未定义此变量,因此它将展开到空字符串。

请注意,变量CP仍将包含$<space>对,直到它扩展。大多数时候,这并不重要,但如果您的makefile取决于使用CCD_ 13来处理底层(未展开)值,上述技术可以提供令人惊讶的结果。

此外,最近发布的GNUMake4.3现在明确地记录了分割线条的技术(https://www.gnu.org/software/make/manual/make.html#Splitting-行):

不添加空白的拆分

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

var := one$
word

在make删除反斜杠/换行符并将以下行压缩为一个空格后,这相当于:

var := one$ word

然后make将执行变量扩展。变量引用"$"指的是一个名为"(空格)的变量,该变量不存在,因此扩展到空字符串,给出一个最终赋值,相当于:

var := oneword

另一种技术是清洗CP的值。这需要GNU Make3.80或更高,因为它依赖于CCD_ 15和CCD_。它使在洗钱过程中使用了一些变量和函数。

首先,将变量empty定义为空字符串spacenewline分别包含一个文字空间和换行符:

empty :=
space := $(empty) $(empty)
define newline

endef

接下来,使用$(eval)以编程方式创建一个递归扩展的变量具有给定值:

# Define recursively expanded variable $1 with value $2.
defineVar = $(eval define $1$(newline)$2$(newline)endef)

并定义函数resubst,用另一个:

# Replace $1 with $2 in $3 until no more changes are made.
resubst = $
$(if $(findstring $1,$3),$
$(call resubst,$
$1,$
$2,$
$(subst $1,$2,$3)),$
$3)

这些足以用任意函数二维定义函数换行符和缩进。一般方法包括三个步骤:

  1. 为函数体准备一行换行符
  2. 用换行符重复替换换行符空间对
  3. 删除所有换行符

函数def删除换行符/空白行递归展开的CCD_ 23的延续通过define/endef:定义的变量

# $1 - name of function to redefine as a normalized single-line function.
def = $
$(call defineVar,$
$1,$
$(subst $(newline),$
$(empty),$
$(call resubst,$
$(newline)$(space),$
$(newline),$
$(newline)$(value $1))))

现在CCD_ 26可以用于后处理递归扩展的变量。对于示例:

define CP
one
two
three
four
endef
$(call def,CP)

现在,$(value CP)将返回所需的onetwothreefour

以上是我的文章"GNU Make-line continuations"的精华:http://drmikehenry.com/gnu-make-line-continuations/

不是真的;反斜杠换行组合被定义为产生一个空格。然而,如果您使用的是GNUMake,您可以简单地使用$(subst : ,:,$(CP))

很抱歉对此进行了解释,但我认为这将为您提供您想要的东西:

CP = .:${HADOOP_HOME}/share/hadoop/common/lib/hadoop-auth-2.2.0.jar:
CP:=$(CP)${HADOOP_HOME}/share/hadoop/hdfs/hadoop-hdfs-2.2.0.jar:
CP:=$(CP)${HADOOP_HOME}/share/hadoop/common/hadoop-common-2.2.0.jar:
CP:=$(CP)${HADOOP_HOME}/share/hadoop/mapreduce/hadoop-mapreduce-client-core-2.2.0.jar:
CP:=$(CP)${HADOOP_HOME}/share/hadoop/mapreduce/lib/hadoop-annotations-2.2.0.jar

这应该将下一行附加到CP的值上,与添加空格的"+="有些不同。

我让它类似于@goodguy5

CP:=${HADOOP_HOME}/share/hadoop/common/lib/hadoop-auth-2.2.0.jar
CP+=$(CP)${HADOOP_HOME}/share/hadoop/hdfs/hadoop-hdfs-2.2.0.jar
CP+=$(CP)${HADOOP_HOME}/share/hadoop/common/hadoop-common-2.2.0.jar
CP+=$(CP)${HADOOP_HOME}/share/hadoop/mapreduce/hadoop-mapreduce-client-core-2.2.0.jar
CP+=$(CP)${HADOOP_HOME}/share/hadoop/mapreduce/lib/hadoop-annotations-2.2.0.jar

最新更新