使用Autotools编译项目(下)

这是一篇旧文,未来会不断把之前写过的文章放到这个博客里面。

autoconf可以帮我们生成configure脚本,替换Makefile中的变量,本文讲解其简单的使用方法。

假设我们有如下代码helloworld.c

#include <stdio.h>

int main() {
		printf("Hello, world!\n");
}

Makefile如下:

version = 1.0
name = helloworld

helloworld: helloworld.c
		$(CC) -o $@ helloworld.c

便形成了一个完整的,非常简单的使用make编译的c项目。那么用autoconf的情况下面如何写呢?首先我们要将Makefile重新命令为Makefile.in,内容如下:

version = @PACKAGE_VERSION@
name = @PACKAGE_NAME@

helloworld: helloworld.c
		$(CC) -o $@ helloworld.c

注意到Makefile.in实际上相当于Makefile的一个模版,里面的@PACKAGE_VERSION@@PACKAGE_NAME@相当于参量,将会被autoconf定义的参量替换。

autoconf需要一个文件做为输入,叫作configure.ac。创建这个文件,内容如下:

AC_INIT([helloworld], [1.0])
AC_CONFIG_FILES([Makefile])
AC_OUTPUT

上面第一行AC_INIT定义了PACKAGE_NAMEPACKAGE_VERSION,第二行告诉autoconf要生成的配置文件名为Makefile,注意autoconf会自动查找 配置文件名*.in这样的文件做为输入模版,并替换里面的参量。因此Makefile对应的模版文件就是我们手写的Makefile.in

第三行告诉autoconf按以上配置输出相关配置文件。下面执行autoconf:

autoreconf

autoreconf实际是一串命令的集合,比执行autoconf要简单。执行完成后,生成了configure文件:

% ls
configure

configure文件将用于生成config.status文件。执行configure:

% ./configure
configure: creating ./config.status
config.status: creating Makefile

生成了config.status。注意到,实际上是config.status负责创建Makefile。看看生成的Makefile内容:

version = 1.0
name = helloworld

helloworld: helloworld.c
		$(CC) -o $@ helloworld.c

我们再过一遍流程:

  1. configure.ac是autoconf的命令输入文件
  2. configure.ac中,我们定义Makefile为待生成的配置文件,因此我们需要有Makefile.in做为模版,里面有待替换的变量
  3. 执行autoreconf生成configure
  4. configure生成config.status
  5. config.status通过Makefile.in生成Makefile

从上面的流程看出什么没?可以发现其实是config.status这个文件负责将Makefile.in转成Makefile。因此,上面的流程执行过一次以后,如果想修改Makefile,只需要修改Makefile.in就可以了,而1-4步可以不必再重复,除非configure.ac需要做出改动。

因此我们可以在Makefile.in中加入用于更新Makefile自身和config.status的rule:

version = @PACKAGE_VERSION@
name = @PACKAGE_NAME@

helloworld: helloworld.c
		$(CC) -o $@ helloworld.c

Makefile: Makefile.in config.status
		./config.status $@

config.status: configure
		./config.status --recheck

这样,当1-5执行过一次后,以后想更新Makefile,只需要修改完Makefile.in后,执行:

% make Makefile
./config.status Makefile
config.status: creating Makefile
make: `Makefile' is up to date.

我将上面的代码放在了github里面,可以clone出来玩玩看:

git clone git://github.com/liweinan/try-make.git

代码位于try02目录。