分类: 嵌入式
2015-01-20 15:25:37
一:
许多读者都知道在linux系统中安装软件的其中一种:源码安装的方法是,先输入./configure,然后输入make,最后make install。或许有人留意到没有,这些软件的根目录中开始是没有Makefile的,在执行了./configure后会生成了很多奇怪名字的文件,当然./configure命令就是执行当前目录的名为configure的脚本,这篇文章就是简单的说说为什么要这样子。
二:
实际操作可以让我们得到更深刻的理解。
假设我们写一个简单的程序poke,它用到utime系统调用来更改文件的访问和修改时间,这个程序必须具备高度的可移植性。
First Try
#include
#include
#include
#include
int main(argc,argv)
int argc;
char **argv;
{
if(argc !=2)
{
fprintf(stderr,"Usage:poke file \n");
exit(1);
}
if(utime(argv[1],NULL)<0)
{
perror("utime");
exit(1);
}
exit(0);
}
CC=gcc
CFLAGS=-g -O2
all:poke
poke:poke.o
$(CC) -o poke $(CFLAGS) $(LDFLAGS) poke.o
目前为止,一个make命令就可以生成poke的可执行文件,so far,so good!不幸的是,这里有几个问题值得深究:
在比较old的BSD4.3派生的unix系统,utime系统调用并不能接受第二个参数NULL,它们需要的是一个struct utimbuf的结构体指针。再追溯到更古老的系统,它们甚至没有定义这个struct,需要传递两个long型的参数。
另外一个问题是stdlib.h是ANSI C所用,老一点的系统也没有这份copy。我们把它包含进来是为了得到exit函数的声明。
在上面的Makefile中,我们甚至都没有提供安装的方法,当然作为例子可能不需要这样做,但实际上我们需要在Makefile里面install跟clean两个伪目标。
Second Try
为了解决上面的问题,我们用预处理命令的宏修改了poke.c文件如下:
#include
#ifdef STDC_HEADERS
#include
#endif
#include
#ifdef HAVE_UTIME_H
#include
#endif
#ifndef HAVE_UTIME_NULL
#include
#ifndef HAVE_STRUCT_UTIMBUF
struct utimbuf
{
long actime;
long modtime;
};
#endif
static int
utime_now (file)
char *file;
{
struct utimbuf now;
now.actime = now.modtime = time (NULL);
return utime (file, &now);
}
#define utime(f, p) utime_now (f)
#endif /* HAVE_UTIME_NULL */
int
main (argc, argv)
int argc;
char **argv;
{
if (argc != 2)
{
fprintf (stderr, "Usage: poke file\n");
exit (1);
}
if (utime (argv[1], NULL) < 0)
{
perror ("utime");
exit (1);
}
exit (0);
}
下面是相应的Makefile,我们添加了预处理标志以及install和clean两个伪目标。
# Set this to your installation directory.
bindir = /usr/local/bin
# Uncomment this if you have the standard ANSI/ISO C header files.
# STDC_HDRS = -DSTDC_HEADERS
# Uncomment this if you have utime.h.
# UTIME_H = -DHAVE_UTIME_H
# Uncomment this if utime (FILE, NULL) works on your system.
# UTIME_NULL = -DHAVE_UTIME_NULL
# Uncomment this if struct utimbuf is defined in utime.h.
# UTIMBUF = -DHAVE_STRUCT_UTIMBUF
CC = gcc
CFLAGS = -g -O2
ALL_CFLAGS = $(STDC_HDRS) $(UTIME_H) $(UTIME_NULL) $(UTIMBUF) $(CFLAGS)
all: poke
poke: poke.o
$(CC) -o poke $(ALL_CFLAGS) $(LDFLAGS) poke.o
.c.o:
$(CC) -c $(ALL_CFLAGS) poke.c
install: poke
cp poke $(bindir)/poke
clean:
rm poke poke.o
从Makefile可以知道,编译安装poke这个软件的用户必须知道自己的系统中utime系统调用是怎么样工作的,然后把Makefile中对应的预处理标志选择上,这又是一个头疼的问题。
Third Try
作为第三次尝试,我们用autoconf和automake工具自动检查配置工具生成Makefile,我们写一个
configure.in的脚本去检测当前系统的配置特性,而不需要用户自己编辑Makefile。
poke.c需要包含config后的头文件config.h
#include "config.h"
1)configure.in脚本
AC_INIT(poke.c)
AM_INIT_AUTOMAKE(poke, 1.0)
AM_CONFIG_HEADER(config.h:config.in)
AC_PROG_CC
AC_HEADER_STDC
AC_CHECK_HEADERS(utime.h)
AC_EGREP_HEADER(utimbuf, utime.h, AC_DEFINE(HAVE_STRUCT_UTIMBUF))
AC_FUNC_UTIME_NULL
AC_OUTPUT(Makefile)
‘AC_HEADER_STDC’
检查标准的C头文件.
‘AC_CHECK_HEADERS’
检查指定的头文件是否存在。
‘AC_EGREP_HEADER’
检查特定头文件里面是否包含特定的字串, in this case checking
for ‘utimbuf’ in ‘utime.h’.
‘AC_FUNC_UTIME_NULL’
Check whether ‘utime’ accepts a NULL second argument to set the ?le change
time to the current time.
2)Makefile.am脚本
bin_PROGRAMS = poke
poke_SOURCES = poke.c
bin_PROGRAMS表明构建一个名为poke的程序,它应当安装在binary目录,己前面提到的bindir目录;
poke_SOURCES表明poke可执行程序需要源文件为poke.c
3)acconfig.h脚本
/* Name of package. */
#undef PACKAGE
/* Version of package. */
#undef VERSION
/* Whether utime.h defines struct utimbuf. */
#undef HAVE_STRUCT_UTIMBUF
4)运行如下命令自动生成其他必备的文件(你的电脑上应该有autoconf/automake/m4/perl/libtool)
panasonic@panasonic-linux:~/devel/poke3> autoscan
configure.in: warning: missing AC_CHECK_FUNCS([utime]) wanted by: poke.c:17
这里autoscan提醒我们configure.in应该加上检查utime函数的选项
panasonic@panasonic-linux:~/devel/poke3> aclocal
panasonic@panasonic-linux:~/devel/poke3> autoconf
panasonic@panasonic-linux:~/devel/poke3> automake -a
Makefile.am: required file `./NEWS' not found
Makefile.am: required file `./README' not found
Makefile.am: required file `./AUTHORS' not found
Makefile.am: required file `./ChangeLog' not found
automake -a参数是--add-missing,意思是automake会自动添加它运行所需文件到当前工程,上面提示当前目录下找不到Makefile.am所需四个文件,NEWS/README/AUTHORS/ChangeLog,作为例子我们暂时忽略它们,加上--foreign选项
panasonic@panasonic-linux:~/devel/poke3> automake -a --foreign
5)当前目录已经产生了好多文件
? ‘aclocal.m4’
? ‘configure’
? ‘config.in’
? ‘Makefile.in’
? ‘stamp-h.in’
然后我们运行./configure脚本
panasonic@panasonic-linux:~/devel/poke3> ./configure
checking for a BSD-compatible install... /usr/bin/install -c
checking whether build environment is sane... yes
checking for a thread-safe mkdir -p... /bin/mkdir -p
checking for gawk... gawk
checking whether make sets $(MAKE)... yes
checking for gcc... gcc
checking for C compiler default output file name... a.out
checking whether the C compiler works... yes
checking whether we are cross compiling... no
checking for suffix of executables...
checking for suffix of object files... o
checking whether we are using the GNU C compiler... yes
checking whether gcc accepts -g... yes
checking for gcc option to accept ISO C89... none needed
checking for style of include used by make... GNU
checking dependency style of gcc... gcc3
checking how to run the C preprocessor... gcc -E
checking for grep that handles long lines and -e... /usr/bin/grep
checking for egrep... /usr/bin/grep -E
checking for ANSI C header files... yes
checking for sys/types.h... yes
checking for sys/stat.h... yes
checking for stdlib.h... yes
checking for string.h... yes
checking for memory.h... yes
checking for strings.h... yes
checking for inttypes.h... yes
checking for stdint.h... yes
checking for unistd.h... yes
checking utime.h usability... yes
checking utime.h presence... yes
checking for utime.h... yes
checking for utime.h... (cached) yes
checking whether utime accepts a null argument... yes
configure: creating ./config.status
config.status: creating Makefile
config.status: creating config.h
config.status: executing depfiles commands
最后产生我们需要的Makefile和config.h
然后运行make,make install就会生成可执行文件然后安装。
autoconf和automake过程关系如下图:
三:构建过程中各种文件
6)程序开发者需要写以下几个脚本
1、configure.in
这是配置脚本,包含autoconf的可执行宏。当然它也可以包含shell命令。这个脚本包含为可移植服务的特性检测,文件的最后AC_OUTPUT宏列举了当用户运行configure脚本需要创建的文件,一般是Makefile。
2、Makefile.am
这是automake的输入文件。它描述了代码是如何构建的。它由automake的变量组成,当然它也可能包含Makefile的目标。这个文件仅是automake需要,新一点的工具可以允许开发者直接写Makefile.in文件。
3、acconfig.h
当configure脚本用AM_CONFIG_HEADER或者AC_CONFIG_HEADER产生了带可移植特性的头文件时,这个文件用来描述那些autoheader命令识别不了宏。通常在configure.in任何一个AC_DEFINE宏都会在这个文件有一行。
4、acinclude.m4
这个文件不是必须的。它定义了本地autoconf宏,这些宏可能用在configure.in里面。如果你不需要任何本地的autoconf宏,你就不需要这个文件,因为你可以把这些需要直接放在configure.in文件里。新一点的工具可能会忽略这个文件,取代的是m4的文件夹,然后在Makefile.am用ACLOCAL_AMFLAGS=-I m4使得aclocal检查里面是否有宏定义。
7)开发文件
1、configure
这是稍后用来构建package的配置脚本。它是autoconf从configure.in 和aclocal.m4产生的,同时它也是一个shell脚本
2、Makefile.in
这是configure脚本生成Makefile的高一级文件,它是由automake从Makefile.am文件产生的。如果你没有用到automake,那你就必须自己来写这个文件。
3、aclocal.m4
它由aclocal程序产生,基于configure.in和acinclude.m4的内容。它包含了autoconf定义的宏,用来产生configure。这些autoconf的宏可能定义在acinclude.m4文件里面,也可能定义在automake或者libtool或者gettext里面。
4、configin
这个文件基于acconfig.h和configure.in,有autoheade产生。在构建时,configure脚本会在它里面定义一些宏来创建config.h,config.h是用来包含进你的应用程序的。它允许你的程序使用预处理条件以便改变你的程序动作适应当前的系统。这个文件也可能名为config.h.in
5、stamp.h-in
automake产生的,它总是包含timestamp字串,它用来标识文件的时间戳以指明config.in是否是最新的。
8)构建文件
1、config.status
安装一个软件第一步骤运行configure脚本,然后它会产生config.status,这也是一个shell脚本。当automake使用Makefile.in产生Makefile时会包含自动运行config.status的规则。
2、Makefile
make会读入然后产生program,config.status运行时候会将Makefile.in翻译成Makefile
3、config.h
这个文件定义了c预处理宏,以便适应不同的移植要求,config.status也会把configin翻译成config.h
4、config.cache
configure脚本运行时缓存,可以加速构建过程。
5、stamp.h
跟stamp-h.in类似。
9)支持文件
1、ABOUT-NLS;2、ansi2knr.c;3、ansi2knr.1;4、config.guess;5、config.sub;6
.....
这里传上文章的练习示例代码包,请大家一起练习学习。
然后是今天的主题:The GNU con?gure and build system