autotools
文章目录
原文地址
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日
有了前面几篇文章介绍的几招,基本的构建系统就算完成了。开始离专业水平还有一定距离。我们现在看看一些后续的方法,让我们的构建脚本更加专业。
- 设置库依赖和预处理宏:
设置依赖库和宏的方法很简单,只要维护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了。生活。。。真美好!
- 检查目标系统上的库:
如何检查目标系统上有没有我们程序依赖的库呢。很简单,在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])
- 部署文件:
目前为止,默认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的更多相关文章
- 在 Linux 中使用 Eclipse 和 Gnu Autotools 管理 C/C++ 项目
在我该系列的之前的所有随笔中,都是采用 Linux 发行版自带的包管理工具(如 apt-get.yum 等)进行软件的安装和卸载,从来没有向大家展示使用源代码自行编译安装软件的方法.但是长期混迹于 U ...
- C/C++ makefile自动生成工具(comake2,autotools,linux),希望能为开源做点微薄的贡献!
序 在linux下C或C++项目开发,Makefile是必备的力气,但是发现手写很麻烦. 在百度有个comake2工具,用于自动生成Makefile工具,而在外边本想找一个同类工具,但发现 ...
- 使用autotools系列工具自动部署源代码编译安装
在Linux系统下开发一个较大的项目,完全手动建立Makefile是一件费力而又容易出错的工作.autotools系列工具只需用户输入简单的目标文件.依赖文件.文件目录等就可以比较轻松地生成Makef ...
- Linux Autotools
/********************************************************************** * Linux Autotools * 说明: * 我们 ...
- GNU Autotools的研究(转)
最近对Linux下软件项目的构建过程研究了一番.Linux下的软件项目通常用Autotools工具集和make工具来构建,我们通常使用./configure.make.make install这样的命 ...
- 如何使用autotools生成Makefile
安装autotools工具sudo apt-get install autoconf 一,四个代码文件init.s lcd.c addr.h uart.c 二,命令:autoscan 三,命令:vi ...
- Makefile自动生成工具-----autotools的使用(详细)
相信每个学习Linux的人都知道Makefile,这是一个很有用的东西,但是编写它是比较复杂,今天介绍一个它的自动生成工具,autotools的使用.很多GNULinux的的软件都是用它生成Makef ...
- autotools入门笔记(一)
GNU autotools作用:收集系统配置信息并自动生成Makefile文件. GNU autotools主要包括三个工具:autoconf.automake.libtool,还有很多辅助的工具,包 ...
- autotools归纳
最近接触到许多linux项目,其编译都是使用的autotools. autotools是一个自动化的编译工具.个人理解它的最主要功能就是生成Makefile. 因为直接写Makefiel,其依赖关系还 ...
- GNU autotools自动生成Makefile 介绍
一.目的 使用autotools工具来帮助我们自动地生成符合自由软件惯例的makefile(这样就可以像常见的GNU程序一样,只要使用"./configure", "ma ...
随机推荐
- 快速测试方法——JUnit
特点:写一个类,里面可以执行多个方法. 在一个方法上面添加@Test,选中方法名,右键run,即可执行当前方法 import org.junit.Test; //注:测试方法要求:不能有返回值,不能有 ...
- 第 8 章 容器网络 - 070 - 如何定制 Calico 网络 Policy?
定制 Calico 网络 Policy Calico 默认的 policy 规则是:容器只能与同一个 calico 网络中的容器通信. Calico 能够让用户定义灵活的 policy 规则,精细化控 ...
- webview元素定位
genymotion 模拟器:android 5.0.0 python 2.7 appium 1.4.16.1 1.app原生元素定位(常用) driver.find_element_by_id(“ ...
- ssh远程登陆和MTR测试
ssh -p 22 root@142.234.255.66 which mtr yum install mtr -y mtr -c 20 -n --report www.baidu.com mtr - ...
- 雷林鹏分享:jQuery EasyUI 数据网格 - 合并单元格
jQuery EasyUI 数据网格 - 合并单元格 数据网格(datagrid)经常需要合并一些单元格.本教程将向您展示如何在数据网格(datagrid)中合并单元格. 为了合并数据网格(datag ...
- guxh的python笔记二:函数基础
1,函数的参数 1.1,查看函数的参数类型 def run(a, *args, b, **kwargs): return a + b 可以通过如下方式查看参数类型: import inspect k ...
- 如何从零开始在github上新建项目
准备工作: (1)安装git: Git-2.16.1-64-bit.exe (2)新建一个文件夹grpc007,作为本地git仓库 (3)进入到grpc007目录,右键/打开git bash.使用gi ...
- 基础模块 网络连接检查 js
//无对象则加载 if (typeof Base == "undefined") Base = function() {} // 获取时间对象的基本方法 Base.prototyp ...
- HTML中引用外部JS文件失效原因
今天在练习中碰到“引用外部的一个js文件但是却失效”的情况,实在不懂,百度后才知是引用的位置不对,错误的代码如下: <head> <meta charset="UTF-8& ...
- mongoose中connect()、createConnection()和connection的区别和作用
转文:原文 1 mongoose简介 在使用mongodb数据库开发项目中,nodejs环境下可能会使用到mongoose模块连接并操作mongodb数据库.mongoose模块相当于Java中的数据 ...