原文地址

http://blog.dccmx.com/2011/page/9/10

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

dccmx 于 2011年 一月 7日 发表 | 最后修改于 2011年 一月 10日
要想弄懂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

dccmx 于 2011年 一月 10日 发表 | 最后修改于 2011年 一月 11日

前面说了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

dccmx 于 2011年 一月 11日 发表 | 最后修改于 2011年 十二月 14日

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

1
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会检查这些文件的。所以,如果不想要的话先建个空文件搪塞一下吧,如果实在受不了也可以用–foreign参数来禁止这个检查。
最后一步,在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——深加工

dccmx 于 2011年 一月 17日 发表 | 最后修改于 2011年 一月 20日

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

  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了。生活。。。真美好!

  1. 检查目标系统上的库:
    如何检查目标系统上有没有我们程序依赖的库呢。很简单,在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])
  1. 部署文件:
    目前为止,默认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看看。

autotools的更多相关文章

  1. 在 Linux 中使用 Eclipse 和 Gnu Autotools 管理 C/C++ 项目

    在我该系列的之前的所有随笔中,都是采用 Linux 发行版自带的包管理工具(如 apt-get.yum 等)进行软件的安装和卸载,从来没有向大家展示使用源代码自行编译安装软件的方法.但是长期混迹于 U ...

  2. C/C++ makefile自动生成工具(comake2,autotools,linux),希望能为开源做点微薄的贡献!

      序     在linux下C或C++项目开发,Makefile是必备的力气,但是发现手写很麻烦. 在百度有个comake2工具,用于自动生成Makefile工具,而在外边本想找一个同类工具,但发现 ...

  3. 使用autotools系列工具自动部署源代码编译安装

    在Linux系统下开发一个较大的项目,完全手动建立Makefile是一件费力而又容易出错的工作.autotools系列工具只需用户输入简单的目标文件.依赖文件.文件目录等就可以比较轻松地生成Makef ...

  4. Linux Autotools

    /********************************************************************** * Linux Autotools * 说明: * 我们 ...

  5. GNU Autotools的研究(转)

    最近对Linux下软件项目的构建过程研究了一番.Linux下的软件项目通常用Autotools工具集和make工具来构建,我们通常使用./configure.make.make install这样的命 ...

  6. 如何使用autotools生成Makefile

    安装autotools工具sudo apt-get install autoconf 一,四个代码文件init.s lcd.c addr.h uart.c 二,命令:autoscan 三,命令:vi ...

  7. Makefile自动生成工具-----autotools的使用(详细)

    相信每个学习Linux的人都知道Makefile,这是一个很有用的东西,但是编写它是比较复杂,今天介绍一个它的自动生成工具,autotools的使用.很多GNULinux的的软件都是用它生成Makef ...

  8. autotools入门笔记(一)

    GNU autotools作用:收集系统配置信息并自动生成Makefile文件. GNU autotools主要包括三个工具:autoconf.automake.libtool,还有很多辅助的工具,包 ...

  9. autotools归纳

    最近接触到许多linux项目,其编译都是使用的autotools. autotools是一个自动化的编译工具.个人理解它的最主要功能就是生成Makefile. 因为直接写Makefiel,其依赖关系还 ...

  10. GNU autotools自动生成Makefile 介绍

    一.目的 使用autotools工具来帮助我们自动地生成符合自由软件惯例的makefile(这样就可以像常见的GNU程序一样,只要使用"./configure", "ma ...

随机推荐

  1. Springboot静态文件不更新的解决办法,以及Springboot实现热部署

    Springboot静态文件不更新的解决办法,以及Springboot实现热部署 原文链接:https://www.cnblogs.com/blog5277/p/9271882.html 原文作者:博 ...

  2. 容器工厂(原型&单例)

    上一篇讲的是容器工厂的原型. 我们可以不必通过new关键之创建实例,可以直接取容器里面的实例. 我们可以发现,在对比他们的地址值的时候,他们是相同的为true. 如果我们需要的是不一样的呢.也就是有一 ...

  3. 《温故而知新》JAVA基础一

    一:基本环境 种类 javaSE(核心语法)+javaME(移动设备)+Java EE(JSP/服务等) JVM(java虚拟机) abc.java(源文件)--编译器--abc.class 字节码文 ...

  4. 决策树算法原理(ID3,C4.5)

    决策树算法原理(CART分类树) CART回归树 决策树的剪枝 决策树可以作为分类算法,也可以作为回归算法,同时特别适合集成学习比如随机森林. 1. 决策树ID3算法的信息论基础   1970年昆兰找 ...

  5. jmeter之接口测试(http接口测试)

    基础知识储备 一.了解jmeter接口测试请求接口的原理 客户端--发送一个请求动作--服务器响应--返回客户端 客户端--发送一个请求动作--jmeter代理服务器---服务器--jmeter代理服 ...

  6. 画一条0.5px的线

    通过伪类元素:after为其添加样式,用transform:scaleY令其在垂直方向缩小0.5倍 .div:after{ height: 1px; transform: scaleY(0.5); t ...

  7. servlet_filter简介

    Filter总结: 1.Filter也称之为过滤器,它是Servlet技术中最激动人心的技术,WEB开发人员通过Filter技术,对web服务器管理的所有web资源:例如Jsp, Servlet, 静 ...

  8. Socket中SO_REUSEADDR详解

    1.一般来说,一个端口释放后会等待两分钟之后才能再被使用,SO_REUSEADDR是让端口释放后立即就可以被再次使用. SO_REUSEADDR用于对TCP套接字处于TIME_WAIT状态下的sock ...

  9. 数据结构与算法之PHP排序算法(希尔排序)

    一.基本思想 希尔排序算法是希尔排序,也称递减增量排序算法,是插入排序的一种更高效的改进版本. 该方法的基本思想是:先将整个待排元素序列分割成若干个子序列(由相隔某个“增量”的元素组成的)分别进行直接 ...

  10. 2015-10-21 C#1

    C#(一) 一.C#的数值类型 byte----字节型 short---短整型 int------整型 long----长整型 char----字符型 float----单精度型 double--双精 ...