在GNU Make中连接列表元素

30
在我的 makefile 中,我有一个包含目录列表的变量,就像这样:
DIRS = /usr /usr/share/ /lib

现在,我需要从中创建PATH变量,这基本上是相同的,但使用分号作为分隔符:

PATH = /usr:/usr/share/:/lib

我该怎么做呢?我的意思是,如何使用分号而不是空格连接DIRS列表中的元素?


https://dev59.com/lmkv5IYBdhLWcg3wewtd - sanmai
3个回答

41
你可以使用$(subst)命令,结合一点技巧获取一个值为单个空格的变量:
p = /usr /usr/share /lib
noop=
space = $(noop) $(noop)

all:
        @echo $(subst $(space),:,$(p))

3
在那里,你也可以使用 $(eval) 而不是 $(noop),从而消除定义 noop 的需要。 - Ivan Tarasov
2
看起来像黑魔法,但在手册中有详细描述。 - hiroshi
实际上,我改变了主意。我认为Dave的$(eval)解决方案更好。它不仅避免了使用$(noop)和$(space)污染变量名称空间。 - Christopher Smith

16

最简洁的表达方式(我能找到的):

classpathify = $(subst $(eval ) ,:,$(wildcard $1))
cp = a b c d/*.jar

target:
    echo $(call classpathify,$(cp))
# prints a:b:c:d/1.jar:d/2.jar

注意:

  • 将它转化成一个伪函数比起在行内进行一堆晦涩的字符串处理更能清楚地表达意图。
  • 注意eval后面有一个空格:$(eval )。没有这个空格,make解释为$(eval)是一个变量而不是调用eval函数。如果省略尾随空格,你可以用some_undefined_variable替换eval并且文本替换仍然会发生。但是,如果你使用--warn-undefined-variable标志运行make,你会收到警告,提示evalsome_undefined_variable未定义。
  • 我包含了$(wildcard)函数,因为当指定classpath时,几乎总是同时使用这两个函数。
  • 确保逗号后面没有额外的空格,否则你会得到像"::a:b:c:d:e"这样的结果。

我想补充一点:现在Java支持“-cp lib / *”语法,因此您可以避免执行$(wildcard $1),这可能是一个好主意,因为Java项目倾向于使用大量的JAR文件,这可能会导致在某些平台上超出长度限制的情况。 - Christopher Smith
2
更通用的形式: joinwith = $(subst $(eval) ,$1,$2) $(call joinwith, -o , $(list_of_files_separated_by_spaces)) - Jay M

3
你使用':'作为分隔符,所以你在使用Linux。考虑使用bash工具链将连续的空格替换为单个冒号。
PATH := $(shell echo $(DIRS) | sed "s/ \+/:/g")

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