在configure.ac中为变量赋值
打开终端时,我可以执行:
igor@IgorReinCloud \~/dbhandler $ set | grep SQLANY\[09\]\*
SQLANY17=/opt/sqlanywhere17
SQLANYSAMP17=/opt/sqlanywhere17/samples
igor@IgorReinCloud \~/dbhandler $
但在 configure.ac 内执行以下操作时:
SQLANY=\`set | grep "SQLANY\[09\]\*"\`
AC_MSG_NOTICE(\[Variable is $SQLANY\])
并重新生成/重新运行configure我得到:
Variable is
我到底做错了什么?
我的目标是得到 Variable is SQLANY17=/opt/sqlanywhere17,然后使用 awk 来解析该值以获取目录。
我无法控制导出的名称,因此需要以某种方式获取路径。 17 那里有版本号,因此我在寻找一个通用的解决方案,使其适用于任意版本。
解决方案
请始终记住,Autoconf的主要工作是生成 configure,它是一个shell脚本。如果 configure 没有按预期工作,你总是有选项直接对其进行调试。你通常会看到大量与Autoconf宏相关的代码,但你的模板文本以及周围生成的代码,应该可以通过文本编辑器的搜索功能不难找到。
当我给它这组来自问题的输入时……
AC_INIT([so_test], [0.0.1])
SQLANY=\`set | grep "SQLANY\[09\]\*"\`
AC_MSG_NOTICE([Variable is $SQLANY])
AC_CONFIG_FILES([Makefile])
AC_OUTPUT
Autoconf生成了一个 configure 脚本,里面包含了相应的代码(以及更多):
SQLANY=\`set | grep "SQLANY\09\\*"\`
{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: Variable is $SQLANY" >&5
printf "%s\n" "$as_me: Variable is $SQLANY" >&6;}
ac_config_files="$ac_config_files Makefile"
运行它产生了以下输出:
grep: warning: stray \ before 0 configure: Variable is configure: creating ./config.status config.status: creating Makefile
,且来自 grep 的信息输出到标准错误,其他信息输出到标准输出。再多做一点实验可以确认你可能预期的那样,当模式解析像那样失败时,grep 不会向标准输出输出任何内容。
这里有几件事在同时发生,但最重要的是,在Autoconf中,成对的方括号([])是引用定界符。反斜杠(\)对Autoconf / M4并不特殊。Autoconf中的引用是一个比人们想象的还要复杂的话题,因此我建议你阅读 Autoconf手册的相关章节。
其次,你尝试使用的实际命令还有一些问题,至少包括
- 你应该偏好现代(有点儿类似的)POSIX命令替换语法。这适用于你所有的脚本和交互式命令,不仅仅是Autoconf的输入。这有若干好处,而且现在也不再算新鲜事。
- 正则表达式
SQLANY[09]*并不等同于你以为它表示的含义。在你的例子中,它只匹配输入的SQLANY部分,而不是数字。你很可能需要SQLANY[0-9]{1,},它在字母之后至少需要一个十进制数字,并且接受从0到9的数字,而不仅仅是端点。 - 我建议在shell代码中使用单引号来进行引用,除非你有充分的理由另作处理,比如你想要变量插值或字面量单引号字符。
总之,这对我有用,而且是我会推荐的写法:
[SQLANY=$(set | grep -E 'SQLANY[0-9]{1,}')]
AC_MSG_NOTICE([Variable is $SQLANY])
这类写法有很多可能的变体,尤其是在变量赋值中哪些部分是用m4引号括起来,以及 grep 命令的确切形式,但我喜欢这一种,因为它清晰、符合良好的shell风格,并且避免GNU的特定特性。