今天装好了longman 5th 和语言岛智能背单词
fedora 18 使用截图-改变很多

Autotools上手指南

molimyi posted @ 2011年12月01日 22:24 in linux with tags automake Autotools上手指南,autoconf , 1956 阅读

本文转自:DCCMX

Autotools上手指南1——autoconf基本思想

要想弄懂Autotools并使用它,必须先要了解一下M4这个怪物。

那么何为M4呢,M4的名称取自Macro(M后面跟4个字母…)。它和C预处理器里的宏是一个概念(其实,M4和C预处理器都K&R操刀设计的!!),用来处理文本替换。也就是说,M4是bash里的预处理器。

取自维基的例子:

divert(-1)
This `divert' discards this text. Note that I had to quote the `divert'
in the comment so it wouldn't get undiverted.
This starts the count at ONE as the incr is a preincrement.
define(`H2_COUNT', 0)
The define H2_COUNT is redefined every time the H2 macro is used.
The dnl deletes everything on the line after it in the output (ie this bit)
define(`H2', `define(`H2_COUNT', incr(H2_COUNT))'dnl
`<h2>H2_COUNT. $1</h2>')
divert(0)dnl diversion to 0 means back to normal dnl removes this line.
H2(First Section)
H2(Second Section)
H2(Conclusion)

这段M4宏用m4处理输出的结果就是:

<h2>1. First Section</h2>
<h2>2. Second Section</h2>
<h2>3. Conclusion</h2>

简单说下:

1.M4的语法跟C里面宏的语法差不多,都很像函数,名字加括号。

2.M4里的参数即使声明了也是可以忽略的,如果一个宏一个参数都不加的话,括号都可以忽略。

懂了吧。就当你懂了。

autoconf就是基于M4这个工具来生成configure脚本的。

我们来看一个最简单的autoconf输入,将下面代码存为configure.ac:

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

再新建一个文件Makefile.in内容如下:

all: @PACKAGE_NAME@_bin

@PACKAGE_NAME@_bin: test.c
    gcc -o @PACKAGE_NAME@_bin test.c

好,下面执行命令:

$ autoconf
$ ./configure

看看,是不是生成了Makefile,是不是下面这样:

all: test_bin

test_bin: test.c
    gcc -o test_bin test.c

中间发生了什么?停我慢慢道来。

首先,autoconf读取configure.ac里的宏,并调用M4处理这些宏,做些检查,如果你很感兴趣,这些宏的实现可以在/usr /share/autoconf/autoconf/*.m4里找到这些宏的定义(看了不要发疯)。检查完会生成两个文件:configure。执行 configure脚本生成config.status和config.log。config.log里面是执行的记录,config.status是下 一步执行的脚本,用来生成Makefile,configure生成完这个脚本会自动调用的。

那Makefile.in又是什么呢?那是第二个宏AC_CONFIG_FILES([Makefile])执行时的默认输入。方括号是用来表示参 数的。就像上面的‘`’一样。Makefile.in就是一个模板,用来生成Makefile。执行configure脚本时(实际上是 config.status脚本),里面的%变量%会被替换成相应的内容。有哪些变量?看看config.log就知道了。

好了,autoconf的基本原理就这样了,本质上就做了件检查环境和变量替换的事。其他的事情以后慢慢讲

Autotools上手指南2——autoscan生成configure.ac

前面说了autotools的基本原理:将configure.ac里的宏展开,运行,生成Makefile。其实,对于大多数项目来 说,configure.ac里的内容基本框架都差不多。既然都差不多那么有没有什么工具可以帮我们做这些基本的事情呢?别忘了你在linux下,有!

autoscan就是干这事的。

下面我们建个test项目吧。目录如下:

test
├── README
└── src
    ├── client.c
    └── server.c

在test目录下运行autoscan看看。是不是生成了如下的configure.scan呢(autoscan.log被我们无情的忽略了):

#                                               -*- Autoconf -*-
# Process this file with autoconf to produce a configure script.

AC_PREREQ([2.68])
AC_INIT([FULL-PACKAGE-NAME], [VERSION], [BUG-REPORT-ADDRESS])
AC_CONFIG_SRCDIR([src/server.c])
AC_CONFIG_HEADERS([config.h])

# Checks for programs.
AC_PROG_CC

# Checks for libraries.

# Checks for header files.
AC_CHECK_HEADERS([netinet/in.h stdlib.h strings.h sys/socket.h unistd.h])

# Checks for typedefs, structures, and compiler characteristics.
AC_TYPE_PID_T

# Checks for library functions.
AC_FUNC_FORK
AC_FUNC_MALLOC
AC_CHECK_FUNCS([bzero socket])

AC_CONFIG_FILES([Makefile])
AC_OUTPUT

我们把这个文件稍微改改,即可用来当做configure.ac了,先将它重命名为configure.ac吧。

我们解释一下这个文件里的一些宏。

首先是,AC_PREREQ([2.68]),这个宏用来检查你机器上的autoconf版本的。这里是我机器上的版本号2.68。

然后AC_INIT宏,这里你要将里面的内容改改,里面的提示你懂的。我们改成下面这样:

AC_INIT([test], [0.1], [dccmx@test.com])

紧跟着是AC_CONFIG_SRCDIR([src/server.c]),这是autoconf用来定位自己的所在目录的宏,里面的内容是所在目录下的任意一个文件就可以了,你可以改成一个更能代表你项目的文件(这样不会更其他项目冲突),也可以不动。

下面是AC_CONFIG_HEADERS([config.h]) 这个是用来生成标准的config.h头文件的宏,这个宏的意思是,从将模板里的@***@变量替换掉生成config.h头文件。模板是什么?默认 是*.in,你记得的(Makefile.in),这里就是config.h.in。我们稍后还会提到。

下面就是一系列的check了,最后是生成Makefile的文件,我们介绍过。

好了,改完了,autoconf命令看看吧。

autoconf如愿生成了configure,运行configure,是不是很标准的输出呢,但是最后提示错了,因为我们还没有添加config.h.in和Makefile.in

Makefile.in文件还像以前的:

all: @PACKAGE_NAME@_client @PACKAGE_NAME@_server
@PACKAGE_NAME@_client:
    gcc -o @PACKAGE_NAME@_client src/client.c
@PACKAGE_NAME@_server:
    gcc -o @PACKAGE_NAME@_server src/server.c

config.h.in呢?我们写一个吧,从上面autoscan生成的configure.ac来看,宏 AC_CHECK_HEADERS([netinet/in.h stdlib.h strings.h sys/socket.h unistd.h])告诉我们的程序调用了这些头文件,那么我们的config.h.in就这样写:

#undef HAVE_NETINET_IN_H
#undef HAVE_STDINT_H
#undef HAVE_STDIO_H
#undef HAVE_STDLIB_H
#undef HAVE_STRING_H
#undef HAVE_SYS_SOCKET_H
#undef HAVE_UNISTD_H
#undef HAVE_NONEXIST_H

看到啦,我们先把这些头文件全都按规则undef掉,我们还加了个系统不存在的头文件试试,现在在运行configure脚本看看,是不是出现了下面的config.h头文件呢:

/* config.h.  Generated from config.h.in by configure.  */
#define HAVE_NETINET_IN_H 1
#define HAVE_STDINT_H 1
#define HAVE_STDIO_H 1
#define HAVE_STDLIB_H 1
#define HAVE_STRING_H 1
#define HAVE_SYS_SOCKET_H 1
#define HAVE_UNISTD_H 1
/* #undef HAVE_NONEXIST_H */

看,所有存在的头文件都被define成了1,不存在的被注释掉。好吧,在你的程序里尽情的include吧,生活真美好。现在可以make生成可执行文件了。test_client和test_server是不是如愿生成了呢?应该是的!

现在我们项目中仍然有两个.in文件要我们自己写:config.h.in和Makefile.in,关于这两个文件的工具,我们后面再谈。拉上老婆出去逛逛吧。歇会儿。

 

Autotools上手指南3——autoheader和automake

前面提到,config.h.in和Makefile.in还要手写,现在我们就来看看,Autotools里有那些工具帮助我们完成这些体力活。
首先是config.h.in。这个非常简单,弄好configure.ac后,直接在项目根目录运行下面命令

autoheader

看看,是不是生成了config.h.in了,看看内容。真轻松啊,autoheader工具分析了configure.ac里面所有要检查的东西,然后生成了相应的宏,好了,可以用了。

Makefile.in的生成就比较复杂了,毕竟Makefile是个复杂的东东。
我坦白,要自动生成Makefile.in以便让configure自动生成Makefile你必须再手动写个Makefile.am文件(这就是灵活的代价和unix的哲学)。
所谓Makefile.am其实就是automake用来生成Makefile.in的模板,里面就像一般的Makefile,只不过加了一些automake宏。
回顾前面的目录结构,我们需要在根目录和所有源码目录添加Makefile.am文件,如下:

test
├── README
├── configure.ac
├── Makefile.am
└── src
    ├── Makefile.am
    ├── client.c
    └── server.c

先来看根目录下的Makefile.am文件:

SUBDIRS = src

灰常简单!
再看src目录下的Makefile.am文件:

bin_PROGRAMS = client server
client_SOURCES = client.c
server_SOURCES = server.c

同样灰常简单,这个文件,不解释,你懂的。现在应该淡定些了。
好,现在我们还需要建一些文件AUTHORS、COPYING、NEWS、ChangeLog和README,这些文件都是gnu项目的标准文件,automake会检查这些文件的。所以,如果不想要的话先建个空文件搪塞一下吧,等automake过了在删也不迟!!
最后一步,在configure.ac里面加上automake支持的宏

#                                               -*- Autoconf -*-
# Process this file with autoconf to produce a configure script.
AC_PREREQ([2.68])
AC_INIT([test], [1.0], [test@dccmx.com])
AM_INIT_AUTOMAKE
AC_CONFIG_SRCDIR([src/server.c])
AC_CONFIG_HEADERS([config.h])
# Checks for programs.
AC_PROG_CC
# Checks for libraries.
# Checks for header files.
AC_CHECK_HEADERS([netinet/in.h stdlib.h strings.h sys/socket.h unistd.h])
# Checks for typedefs, structures, and compiler characteristics.
AC_TYPE_PID_T
# Checks for library functions.
AC_FUNC_FORK
AC_FUNC_MALLOC
AC_CHECK_FUNCS([bzero socket])
AC_CONFIG_FILES([Makefile src/Makefile])
AC_OUTPUT

看到了,我们现在初始化部分加了AM_INIT_AUTOMAKE 来初始化automake,在最后又改了AC_CONFIG_FILES([Makefile src/Makefile]) ,来吧src目录下的Makefile也加入管理。
好了,都准备好了,开始干活:

dccmx@~/projects/console/test$ aclocal
dccmx@~/projects/console/test$ autoconf
dccmx@~/projects/console/test$ autoheader
dccmx@~/projects/console/test$ automake –a –c
dccmx@~/projects/console/test$ make

神清气爽啊。在src目录里生成两个二进制文件了。make distclean看看?一切恢复如初!make dist看看,自动打包发布。生活真是美好啊。
等等,第一个命令是干什么的呢,这个命令是用来生成automake依赖的宏的,供autoconf调用(因为automake其实不是autoconf 的一部分,只相当于插件)。automake后面的两个参数又是干什么的呢?因为automake生成的Makefile需要一些外部脚本辅助,而项目里 是没有的,所以-a就是把这些文件自动添加就来,-c就是指定用复制的方式添加,否则是符号链接。
好了,基本的autotools的介绍就这些了。更高级的话题,后面有时间再谈吧。洗洗睡了。

Autotools上手指南4——深加工

有了前面几篇文章介绍的几招,基本的构建系统就算完成了。开始离专业水平还有一定距离。我们现在看看一些后续的方法,让我们的构建脚本更加专业。

1.设置库依赖和预处理宏:

设置依赖库和宏的方法很简单,只要维护gcc的参数就ok了。这些参数在Makefile.am里面维护。

先在configure.ac里面加上相关的宏:AM_PROG_CC_C_O。

要添加预处理宏的话(比如_GNU_SOURCE宏)只要在Makefile.am里面添加xxx_CFLAGS = -D_GNU_SOURCE。好了。重新configure吧。

依赖的库呢?你猜对了,在Makefile.am里面添加xxx_LDFLAGS = -lssl -lidn -lz就ok了。生活。。。真美好!

2.检查目标系统上的库:

如何检查目标系统上有没有我们程序依赖的库呢。很简单,在configure.ac里面加上AC_CHECK_LIB宏。其实autoscan会检 查Makefile.am中的_LDFLAGS而自动在configure.ac里面添加相关的check宏的。这个宏的原型如下:

AC_CHECK_LIB(library, function, [action-if-found], [action-if-not-found], [other-libraries])


中间的function可以选择lib里面最典型的一个函数,用来测试找到的lib是不是你要的lib,你懂的。举个例子:

AC_CHECK_LIB([ssl], [SSL_get_peer_certificate], [have_ssl=yes])


在在下面加入:

if test "x${have_ssl}" = xno; then
AC_MSG_ERROR([
------------------------------------------
Unable to find ssl on this system.
------------------------------------------])
fi

好了,找不到libssl,或者libssl不对(里面没有SSL_get_peer_certificate),就会提示了。

检查头文件呢?你猜对了。

AC_CHECK_HEADER(header-file, [action-if-found], [action-if-not-found], [includes])

3.部署文件:

目前为止,默认make install已经可以将我们的bin文件安装到/usr/local/bin下了(可以用–prefix改)。如果我们要安装其他文件呢,比如默认配置文件啊等等。

比如我们在xml目录下有a.xml b.xml要安装到默认的@data@/xml目录下(默认是/usr/local/share)。

第一步,在xml目录下建Makefile.am。内容如下:

xmldir = $(datadir)/xml
xml_DATA = a.xml b.xml

第二步,在configure.ac里面的AC_CONFIG_FILES([Makefile src/Makefile]) 加上这个Makefile,改成AC_CONFIG_FILES([Makefile src/Makefile xml/Makefile])

第三步,重新autoconf,automake。其实只要一个命令autoreconf就行了。这个命令会替你调用autoheader和automake的。

想要make dist的时候包含到压缩包里?在xml_DATA前面加上dist变成:dist_xml_DATA就ok了。

好了,make install看看。




  • 无匹配

登录 *


loading captcha image...
(输入验证码)
or Ctrl+Enter