Makefile gnumake:shell cat文件生成的内容没有换行符

Makefile gnumake:shell cat文件生成的内容没有换行符,makefile,gnu-make,Makefile,Gnu Make,生成文件: .PHONY: all SHELL:=/usr/bin/env bash all: $(eval x=$(shell cat file)) @echo "$x" 文件: 输出: foo bar 如何在不丢失换行符的情况下将文件内容放入make变量?如中所述,不能使用shell执行此操作 但是,如果您有足够新的GNU make版本,则可以使用。make将新行从shell输出转换为空格(请参阅): shell函数执行与反引号(“`”)相同的函数 在大多数shell中

生成文件:

.PHONY: all
SHELL:=/usr/bin/env bash
all:
    $(eval x=$(shell cat file))
    @echo "$x"
文件:

输出:

foo bar


如何在不丢失换行符的情况下将文件内容放入make变量?

如中所述,不能使用
shell执行此操作


但是,如果您有足够新的GNU make版本,则可以使用。

make将新行从
shell
输出转换为空格(请参阅):

shell函数执行与反引号(“`”)相同的函数 在大多数shell中执行:它执行命令扩展。这意味着 将shell命令作为参数,并计算为的输出 命令。对结果进行的唯一处理是转换 每个换行符(或回车/换行符对)到单个空格。如果 有一个尾随(回车和)换行符,它将是简单的 删除

因此,不能直接从
$(shell)
命令中保留空格。也就是说,make确实允许使用define来定义多行变量,但是要注意,尝试使用这样的变量是有问题的。考虑:

define x
    foo
    bar
endef

all:
     @echo "$x"
Make将$x展开到位,您将得到:

all:
    @echo "    foo
    bar"
(其中换行符被视为配方行的结尾…)

根据您的目的,您可以通过使用bash变量来解决此问题:

all:
    @x=$$(cat file); \
    echo $$x
或者可能将输出存储在文件中,并在必要时引用该文件

all:
    eval (cat file >> output.txt)
    cat output.txt

(是的,最后一个代码写得很复杂,但我不确定您想做什么,这允许命令的输出跨配方行持久化)。

如果确保文件内容不包含任何二进制数据,并且如果您愿意在每次访问变量时进行额外处理,那么您可以:

foo:=$(shell cat file | tr '\n' '\1')

all:
    @echo "$(shell echo "$(foo)" | tr '\1' '\n')"

请注意,您不能使用null
\0
,我怀疑这可能意味着我的Make副本中存在缓冲区溢出错误。

您不能。该行为在中有清楚的描述,我们也能够通过配方部分中的“$$()”调用来实现我(旧)版本的make的目的。当然,如果您真正想要的只是在shell中有值,而不是在make变量中,那么您可以只使用shell构造,如
$$()
并且根本不使用make函数。有时,你会陷入某种思维方式。作为make变量传递将对submake有用;特别是如果submake无法访问该文件。因此,file命令是完整的解决方案
foo:=$(shell cat file | tr '\n' '\1')

all:
    @echo "$(shell echo "$(foo)" | tr '\1' '\n')"