是否可以在Makefile中创建多行字符串变量

jon*_*ner 110 variables makefile

我想创建一个多行字符串的makefile变量(例如电子邮件发布公告的正文).就像是

ANNOUNCE_BODY="
Version $(VERSION) of $(PACKAGE_NAME) has been released

It can be downloaded from $(DOWNLOAD_URL)

etc, etc"
Run Code Online (Sandbox Code Playgroud)

但我似乎找不到办法做到这一点.可能吗?

Eri*_*ski 161

是的,您可以使用define关键字声明一个多行变量,如下所示:

define ANNOUNCE_BODY
Version $(VERSION) of $(PACKAGE_NAME) has been released.

It can be downloaded from $(DOWNLOAD_URL).

etc, etc.
endef
Run Code Online (Sandbox Code Playgroud)

棘手的部分是让你的多行变量退出makefile.如果您只是使用"echo $(ANNOUNCE_BODY)"这一显而易见的事情,您将看到其他人在此处发布的结果 - shell尝试将变量的第二行和后续行作为命令本身处理.

但是,您可以将变量值按原样导出到shell作为环境变量,然后将其作为环境变量(不是make变量)从shell引用.例如:

export ANNOUNCE_BODY
all:
    @echo "$$ANNOUNCE_BODY"
Run Code Online (Sandbox Code Playgroud)

注意使用$$ANNOUNCE_BODY,表示shell环境变量引用,而不是$(ANNOUNCE_BODY),这将是一个常规的make变量引用.还要确保在变量引用周围使用引号,以确保shell本身不会解释换行符.

当然,这个特殊技巧可能是平台和shell敏感的.我在Ubuntu Linux上使用GNU bash 3.2.13进行了测试; 因人而异.

  • 实际上,这不适用于标准品牌,只有gnu品牌. (3认同)

mal*_*ook 23

"让你的多行变量退出makefile"的另一种方法(由Eric Melski称为"棘手的部分")是计划使用该subst函数替换define多行字符串中引入的换行符\n.然后使用-e with echo来解释它们.您可能需要设置.SHELL = bash以获得执行此操作的回显.

这种方法的一个优点是你还可以将其他类似的转义字符放入文本中并使其得到尊重.

这种综合了到目前为止提到的所有方法......

你结束了:

define newline


endef

define ANNOUNCE_BODY=
As of $(shell date), version $(VERSION) of $(PACKAGE_NAME) has been released.  

It can be downloaded from $(DOWNLOAD_URL).  

endef

someTarget:
    echo -e '$(subst $(newline),\n,${ANNOUNCE_BODY})'
Run Code Online (Sandbox Code Playgroud)

请注意,最终回波上的单引号至关重要.

  • 请注意,"echo -e"不可移植.您应该更喜欢printf(1). (4认同)
  • 但是,我必须在`define ANNOUNCE_BODY`之后删除`=`以使其运行. (2认同)

小智 12

假设您只想在标准输出上打印变量的内容,还有另一种解决方案:

do-echo:
    $(info $(YOUR_MULTILINE_VAR))
Run Code Online (Sandbox Code Playgroud)


Cha*_*tin 7

是的。您可以使用以下命令转义换行符\

VARIABLE="\
THIS IS A VERY LONG\
TEXT STRING IN A MAKE VARIABLE"
Run Code Online (Sandbox Code Playgroud)

更新

啊,你想要换行符吗?那么不,我认为香草制作没有任何办法。但是,您始终可以在命令部分使用此处文档

[这不起作用,请参阅 MadScientist 的评论]

foo:
    echo <<EOF
    Here is a multiple line text
    with embedded newlines.
    EOF
Run Code Online (Sandbox Code Playgroud)

  • 配方中的多行文档在任何支持 POSIX 标准的 make 标准版本中都不起作用:make 标准要求配方的每个单独行必须在单独的 shell 中运行。Make 不会对命令进行任何解析来判断它是否是此处文档,并以不同的方式处理它。如果您知道确实支持此功能的 make 的某些变体(我从未听说过),您可能应该明确说明。 (5认同)

mlo*_*o55 5

与OP不完全相关,但希望这对将来的人有帮助。(因为这个问题是谷歌搜索中出现最多的问题)。

在我的 Makefile 中,我想将文件的内容传递给 docker build 命令,经过一番惊愕之后,我决定:

 base64 encode the contents in the Makefile (so that I could have a single line and pass them as a docker build arg...)
 base64 decode the contents in the Dockerfile (and write them to a file)
Run Code Online (Sandbox Code Playgroud)

请参见下面的示例。

注意:在我的特定情况下,我想在映像构建过程中传递 ssh 密钥,使用https://vsupalov.com/build-docker-image-clone-private-repo-ssh-key/中的示例(使用多阶段 docker 构建来克隆 git 存储库,然后在构建的第二阶段中从最终映像中删除 ssh 密钥)

生成文件

...
MY_VAR_ENCODED=$(shell cat /path/to/my/file | base64)

my-build:
    @docker build \
      --build-arg MY_VAR_ENCODED="$(MY_VAR_ENCODED)" \
      --no-cache \
      -t my-docker:build .
...
Run Code Online (Sandbox Code Playgroud)

Dockerfile

...
ARG MY_VAR_ENCODED

RUN mkdir /root/.ssh/  && \
    echo "${MY_VAR_ENCODED}" | base64 -d >  /path/to/my/file/in/container
... 
Run Code Online (Sandbox Code Playgroud)