Autoconf 能够产生一份 Shell 脚本。对于大部分类 Unix 系统,这份 Shell 脚本可以自动配置软件源码包的构建环境。这份 Shell 脚本就是 Linux 系统中大名鼎鼎的 configure 脚本。segmentfault
在 Linux 系统中,只要你打算以编译源码的方式安装软件包,一般要借助 configure 脚本构建软件源码包的编译环境,除非是某个基于 CMake 或 SCons 构建的软件源码包。迄今为止 Autoconf 所属的 GNU Autotools 依然是类 Unix 系统中主流的项目构建工具,而且也是 Linux 系统中软件源码构建工具的事实标准。bash
与同类相比,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 程序:code
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 脚本中:get
$ 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 支持中文宏名了,即:it
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