错误 `*** 缺少分隔符。 Stop.`:Ubuntu 和 MacO 上的 GNU Make 序言中的 if 语句是否存在细微差别?
Error `*** missing separator. Stop.`: Is there a subtle difference in if statements in GNU Make preambles on Ubuntu and MacOs?
当我运行 makefile
SHELL=/bin/bash
a = False
ifeq ("", "")
a = True
endif
#b = False
#ifeq("","")
# b = True
#endif
#c = False
#if [ "" == "" ] \
#then \
# c = True \
#fi
#d = False
#if [[ "" == "" ]] \
#then \
# d = True \
#fi
all :
@\
echo a = $(a); \
echo b = $(b); \
echo c = $(c); \
echo d = $(d); \
\
c_loc=False; \
if [ "" == "" ]; \
then \
c_loc=True; \
fi; \
\
d_loc=False; \
if [[ "" == "" ]]; \
then \
d_loc=True; \
fi; \
\
echo c_loc = $${c_loc}; \
echo d_loc = $${d_loc}; \
我得到了输出
a = True
b =
c =
d =
c_loc = True
d_loc = True
在 Ubuntu 20.04 上使用 GNU Make 4.2.1 时取消注释 if 语句 c 或 d 会导致错误 Makefile:n: *** missing separator. Stop.
。 n
是if语句c或d的行号。
另一方面,如果我 运行 在 Mac OS Big Sur v11.6.1 和 GNU Make3.81 上使用相同的 makefile(带有 if 语句 c 和 d 未注释)我得到输出
a = True
b =
c = False
d = False
c_loc = True
d_loc = True
取消注释 if 语句 b 导致两个设置中缺少分隔符错误。
我的问题:
- 为什么我在一个设置中收到 if 语句 c 和 d 的缺少分隔符错误,而在另一个设置中却没有?这是由于 GNU Make 3 和 GNU Make 4 之间的差异还是 Ubuntu 和 MacOs 之间的差异?
- 为什么我在两个设置中都没有得到 if 语句 c 和 d 的 True 输出?我在哪里可以找到有关在序言中使用了 shell 的信息?
我不知道你所说的“序言”是什么意思;生成文件中没有“序言”之类的东西。 Makefile 不是 shell 脚本,尽管它们在食谱中包含 shell 脚本。唯一可以使用 shell 脚本语法的地方是食谱。自 1970 年代发明 make 以来,情况一直如此。 if [...]; then; fi
等内容是 shell 脚本语法,因此它只能出现在食谱中。
如果你想在食谱之外使用 if 语句,你必须使用 makefile syntax,而不是 shell 语法。
至于为什么它在 GNU make 3.81 中“有效”(注意,它 真的 无效,因为它不会重置 c
变量,不管你在条件中输入什么值),这是因为在旧版本的 GNU 中,过去创建由空格组成的变量名是合法的。所以这个:
c = False
if [ "" == "" ] \
then \
c = True \
fi
被解释为这两行(反斜杠换行减去后):
c = False
if [ "" == "" ] then c = True fi
在旧版本的 GNU make 中,变量名可以包含空格,这会将名为 if [ "" == "" ] then c
的变量设置为值 True fi
。这是合法的语法,但它显然没有达到您的预期。
在较新版本的 GNU make 中,我们不允许变量名包含空格,因此上面的文本是无效语法,您会得到 make 的标准语法错误缺少分隔符.
当我运行 makefile
SHELL=/bin/bash
a = False
ifeq ("", "")
a = True
endif
#b = False
#ifeq("","")
# b = True
#endif
#c = False
#if [ "" == "" ] \
#then \
# c = True \
#fi
#d = False
#if [[ "" == "" ]] \
#then \
# d = True \
#fi
all :
@\
echo a = $(a); \
echo b = $(b); \
echo c = $(c); \
echo d = $(d); \
\
c_loc=False; \
if [ "" == "" ]; \
then \
c_loc=True; \
fi; \
\
d_loc=False; \
if [[ "" == "" ]]; \
then \
d_loc=True; \
fi; \
\
echo c_loc = $${c_loc}; \
echo d_loc = $${d_loc}; \
我得到了输出
a = True
b =
c =
d =
c_loc = True
d_loc = True
在 Ubuntu 20.04 上使用 GNU Make 4.2.1 时取消注释 if 语句 c 或 d 会导致错误 Makefile:n: *** missing separator. Stop.
。 n
是if语句c或d的行号。
另一方面,如果我 运行 在 Mac OS Big Sur v11.6.1 和 GNU Make3.81 上使用相同的 makefile(带有 if 语句 c 和 d 未注释)我得到输出
a = True
b =
c = False
d = False
c_loc = True
d_loc = True
取消注释 if 语句 b 导致两个设置中缺少分隔符错误。
我的问题:
- 为什么我在一个设置中收到 if 语句 c 和 d 的缺少分隔符错误,而在另一个设置中却没有?这是由于 GNU Make 3 和 GNU Make 4 之间的差异还是 Ubuntu 和 MacOs 之间的差异?
- 为什么我在两个设置中都没有得到 if 语句 c 和 d 的 True 输出?我在哪里可以找到有关在序言中使用了 shell 的信息?
我不知道你所说的“序言”是什么意思;生成文件中没有“序言”之类的东西。 Makefile 不是 shell 脚本,尽管它们在食谱中包含 shell 脚本。唯一可以使用 shell 脚本语法的地方是食谱。自 1970 年代发明 make 以来,情况一直如此。 if [...]; then; fi
等内容是 shell 脚本语法,因此它只能出现在食谱中。
如果你想在食谱之外使用 if 语句,你必须使用 makefile syntax,而不是 shell 语法。
至于为什么它在 GNU make 3.81 中“有效”(注意,它 真的 无效,因为它不会重置 c
变量,不管你在条件中输入什么值),这是因为在旧版本的 GNU 中,过去创建由空格组成的变量名是合法的。所以这个:
c = False
if [ "" == "" ] \
then \
c = True \
fi
被解释为这两行(反斜杠换行减去后):
c = False
if [ "" == "" ] then c = True fi
在旧版本的 GNU make 中,变量名可以包含空格,这会将名为 if [ "" == "" ] then c
的变量设置为值 True fi
。这是合法的语法,但它显然没有达到您的预期。
在较新版本的 GNU make 中,我们不允许变量名包含空格,因此上面的文本是无效语法,您会得到 make 的标准语法错误缺少分隔符.