【问题标题】:How do I properly escape data for a Makefile?如何正确转义 Makefile 的数据?
【发布时间】:2011-12-01 01:09:36
【问题描述】:

我正在使用 bash 脚本动态生成 config.mk,Makefile 将使用该脚本。该文件由以下内容构成:

cat > config.mk <<CFG
SOMEVAR := $value_from_bash1
ANOTHER := $value_from_bash2
CFG

如何确保生成的文件确实包含$value_from_bash* 的内容,而不是扩展/解释的内容?我可能需要将$ 转义到$$\\\,但是还有其他字符需要转义吗?也许有一个我没听说过的特殊字面任务?

空格似乎也很麻烦:

$ ls -1
a b
a
$ cat Makefile
f := a b
default_target:
    echo "$(firstword $(wildcard ${f}))"
$ make
a

如果我使用f := a\ b 它可以工作(使用f := 'a b' 之类的引号也不起作用,makefile 只是将其视为常规字符)

【问题讨论】:

  • 你使用的是什么版本的 Make?
  • 这不是 Makefile 问题,而是 bash 问题。我想你知道你希望你的 makefile 是什么样子,所以你的问题是在你的 bash here-document 中转义东西。看看这个tldp.org/LDP/abs/html/here-docs.html
  • 不,我不是在问如何替换 bash 中的字符串,而是在不修改含义的情况下如何在 Makefile 中从 bash 获取字符串(例如,如果 echo "$var" 显示 "whatever \',则同样应该显示在 Makefile 中)

标签: bash makefile escaping


【解决方案1】:

这个问题的完整答案似乎在互联网上找不到,所以我终于坐下来为 Windows 案例找出答案。

具体来说,“Windows 大小写”是指在 Windows 中有效的文件名,这意味着它们包含字符 \/*?"^&lt;&gt;| 或换行符。这也意味着 \/ 对于 Make 而言都被视为有效的目录分隔符。

一个例子比我能解释的更清楚。基本上,如果您尝试匹配此文件路径:

Child\a$b  {'}(a.o#$@,&+=~`),[].c

那么你必须编写这些规则:

all: Child\\a$$b\\\ \\\ {'}(a.o\#$$@,&+=~`),[].o

%.o: %.c
    $(CC) '$(subst ','"'"',$(subst \,,$(subst \\,/,$+)))'

盯着它看很长时间,它会开始有点遥远的感觉。

这适用于我的 MSYS2 环境,所以我认为它是正确的。

【讨论】:

  • 这种替换模式看起来很奇怪,在语法上有效吗?它似乎将' 替换为'"'"'(在将` by /), is that correct? Oh, basically you are replacing '` 替换为' 之后,然后引用文字"'",然后继续在参数之前和之后开始的单引号。您对此转义有一些参考吗?
  • @Lekensteyn:是的,[stackoverflow.com/a/1250279/541686](here)。然而,这是迄今为止这个问题最简单的方面。真正的困难不是弄乱空格和其他字符,而且我认为我的答案在某些情况下仍然失败......我会在有更好的时候更新它。
  • 啊,是的,这是 sh 风格的转义,不一定适用于 Windows 命令。 IIRC ^ 是 Windows 中使用的转义字符(批处理脚本)。
  • @Lekensteyn:实际上这不是用于批处理脚本,而是用于 sh 样式的转义......但在 Windows (MSYS2) 而不是 Linux 上。很抱歉造成混乱,我发布答案的主要原因是我自己在寻找它,而不是我认为它一定会对您的情况有所帮助。
  • 是的,它可以工作,但前提条件被认为不存在,并且会发生冗余编译。
【解决方案2】:

好吧,事实证明 Makefiles 本身几乎不需要转义,但是由 shell 解释器执行的命令需要进行转义。

在 Makefile 中有特殊含义需要转义的字符有:

  • 尖锐(#,评论)变为\#
  • 美元($,变量的开头)变为$$

不能在变量中插入换行符,但为避免破坏 Makefile 的其余部分,请在其前面加上反斜杠,以便忽略换行符。

太糟糕了,反斜杠本身无法转义(\\ 仍将是 \\,而不是您可能期望的 \)。这使得不可能在字符串的末尾放置一个文字斜杠,因为它会吃掉换行符或后面注释的哈希值。空格可以放在行尾,但也可以放在变量本身中。

配方本身被解释为一个 shell 命令,没有任何花哨的转义,所以你必须自己转义数据,想象你正在编写一个 shellscript 并插入来自其他文件的变量。这里的策略是将变量放在单引号之间,并且只用'\'' 转义'(关闭字符串,插入文字' 并开始一个新字符串)。示例:mornin' all 变为 'morning'\'' all',相当于 "morning' all"

第一个单词+通配符问题是由于firstword 将带有空格的文件名视为单独的文件名而引起的。此外,wildcard 使用\ 扩展转义,因此x\ y 匹配为一个单词,x y 而不是两个单词。

【讨论】:

【解决方案3】:
  1. 我看不出那个 makefile 是如何像你说的那样工作的。模式规则不能是默认值。
  2. 您在 `$(wildcard ...)` 中缺少一个 `$`,所以我认为您没有发布您真正测试的内容。
  3. 您也应该转义换行符。

【讨论】:

  • 感谢您的回答,我在制作示例时确实打错了。只转义换行符、空格、美元和反斜杠就足够了吗?
  • @Lekensteyn,我想是的。但是您可能想重新考虑您的设计; Make 从未真正用于核心字符串操作。
  • 变量实际上是文件路径。通常,这些不包含特殊字符,如换行符(因此我将忽略)、$(但你永远不会确定)。可能需要注意的特殊字符是"' 和空格。
  • 能否通过汇总要转义的字符列表来改进答案?
猜你喜欢
  • 2020-12-10
  • 2012-04-03
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多