Autoconf 可以产生一份 Shell 脚本。对于大部分类 Unix 系统,这份 Shell 脚本能够自动配置软件源码包的构建环境。这份 Shell 脚本就是 Linux 系统中大名鼎鼎的 configure 脚本。
在 Linux 系统中,只要你打算以编译源码的方式安装软件包,通常要借助 configure 脚本构建软件源码包的编译环境,除非是某个基于 CMake 或 SCons 构建的软件源码包。迄今为止 Autoconf 所属的 GNU Autotools 依然是类 Unix 系统中主流的项目构建工具,并且也是 Linux 系统中软件源码构建工具的事实标准。
与同类相比,GNU Autotools 最大的特点是不重新发明轮子,它完全基于 GNU M4 与 Bash Shell 语言(实际上还有 Perl)开发而成。此外,基于 GNU Autotools 发布的软件,它的构建环境配置以及构建过程不再依赖 GNU Autotools,这一点是 CMake 与 SCons 们无法做到的。
要知道 Autoconf 如何生成 Shell 脚本,你至少要具备一丁点 Shell 脚本与 M4 的知识。在此,Shell 脚本指的是 Bash Shell 脚本,有关它的一些知识可以阅读『用几分钟学习 Bash』;M4 指的是 GNU M4,它的一些知识可以阅读『让这世界再多一份 GNU m4 教程』。
现在假设你已经具备了这些基础知识。下面是我写的一段很简单的 Shell 代码,它可以检测系统中是否安装了 foo 程序:
if [ $(which foo) ]
then
echo "checking foo ... yes!"
else
echo "You should install foo!"
exit -1
fi
现在,我用 M4 给上述 Bash 代码制作一个『界面』:
define(`检测系统中是否已安装 foo', `
if [ $(which foo) ]
then
echo "checking foo ... yes!"
else
echo "You should install foo!"
exit -1
fi
')
所谓的『界面』,就是宏 检测系统中是否已安装 foo
。当 GNU m4 读到这个宏时,它就会自动将其展开为它所封装的 Bash 代码。为了说明这一点,请将上述 M4 代码放到一份名为 check-foo.m4 的文件中,然后在一份名为 configure.ac 的文件中写出以下代码:
include(check-foo.m4)
检测系统中是否已安装 foo
然后用 GNU m4 读入这个 configure.ac 文件,并将展开结果写入到一份名为 configure 的 Bash 脚本中:
$ m4 configure.ac > configure
结果就在 configure 文件中获得了 检测系统中是否已安装 foo
这个宏的展开结果:
if [ $(which foo) ]
then
echo "checking foo ... yes!"
else
echo "You should install foo!"
exit -1
fi
如果你得不到上述结果,是因为我欺骗了你。虽然 m4 允许使用中文宏名,但是它不认为这是真的宏名。你可以将 检测系统中是否已安装 foo
改为 check-foo
,这样 m4 就认为它是真正的宏了。也可以使用 GNU M4 提供的间接宏调用功能,这样就可以迂回的使得 m4 支持中文宏名了,即:
indir(`检测系统中是否已安装 foo')
现在,我认为我已经回答了『autoconf 是如何生成 Shell 脚本的』这个问题,你只需要将上述的 m4
命令视为 autoconf
即可。也就是说,autoconf 本质上就是 m4——穿了外套的 m4。
当 autoconf 将 configure.ac 文件中的宏展开为 Bash 代码并将其存储于 configure 脚本之后,以后执行 configure 脚本时,就与 autoconf 无关了。而且,我将 configure 脚本传给他人使用,他们也不需要 autoconf。
这就是 autoconf 运作的基本原理。然而很多人被这个基本原理吓走了,因为他们看见 M4 与 Shell 语言就头大!
如果看到这里你依然不觉得害怕,那么我就可以放心的将上文中的那个 Bash 代码片段做成一个真正的 Autoconf 宏了。所谓的 Autoconf 宏,它本质上就是 M4 宏——穿了外套的 M4 宏。
下面,我要创建一个目录,叫 m4,在这个目录中放置 check-foo.m4 文件,然后将 check-foo.m4 文件的内容修改为:
AC_DEFUN([CHECK_FOO],
[if [[ $(which foo) ]]
then
echo "checking foo ... yes!"
else
echo "You should install foo!"
exit -1
fi])
这里的 CHECK_FOO
是一个 Autoconf 宏,它与前文中的那个 M4 宏 检测系统中是否已安装 foo
本质上是一样的。二者的定义有区别的地方就在于:
-
AC_DEFINE
取代了define
; -
[
取代了 M4 的左引号,]
取代了 M4 的右引号; -
CHECK_FOO
取代了检测系统中是否已安装 foo
; -
[[ $(which foo) ]]
取代了[ $(which foo) ]
,这一点需要了解 M4 的工作原理。
这些『取代』,是 M4 所允许的,也就是说,这一切只用 M4 就能够做到。
接下来,再将 configure.ac 文件修改为:
AC_INIT
CHECK_FOO
然后,在 configure.ac 文件所在的目录执行以下命令:
$ aclocal -I m4
$ autoconf
$ ./configure
如果你的系统中没有 foo 程序,就可以得到这样的结果:
which: no foo in (/bin:/usr/bin:/usr/local/bin)
You should install foo!
上述过程,只有两点需要略做说明。首先,configure.ac 文件中出现的 AC_INIT
宏会被 autoconf 展开为很长的一段 Bash 代码,用于初始化软件源码构建环境;其次,aclocal
命令负责收集 M4 文件的路径信息并将其存储于 aclocal.m4 文件中。
在执行 autoconf
命令时,它会自动读取 configure.ac 文件,然后根据 aclocal.m4 文件中记录的 M4 文件,去寻找 configure.ac 中出现的宏的定义然后进行展开,展开结果就是 configure 脚本。执行 configure 脚本,除了会执行 AC_INIT
所展开的 Bash 代码,还执行了 CHECK_FOO
所展开的:
if [ $(which foo) ]
then
echo "checking foo ... yes!"
else
echo "You should install foo!"
exit -1
fi
**粗体** _斜体_ [链接](http://example.com) `代码` - 列表 > 引用
。你还可以使用@
来通知其他用户。