GNU Autotools的研究

   最近对Linux下软件项目的构建过程研究了一番。Linux下的软件项目通常用Autotools工具集和make工具来构建,我们通常使用./configure、make、make install这样的命令来编译安装软件包,则这样的项目一般就是使用Autotools工具集来构建,再加上GNU make工具来编译安装。
   使用Autotools的目的:
  (1)构建可移植的软件包。在不同操作系统上(主要是不同的类Unix系统),可能同样功能函数名称的不同,同样功能的库的名字的不同,以及头文件的不同,使得软件包的移植成了大的问题。
  (2)统一构建过程。对软件包的编译方式、编译方法进行统一化,以便于项目的构建。
  (3)快速制作Makefile文件。Linux下的项目一般用make工具来管理,需要编写Makefile文件。对于一个较大的项目而言,完全手动建立Makefile是一件费力而又容易出错的工作。autotools系列工具只需用户输入简单的目标文件、依赖文件、文件目录等就可以比较轻松地生成Makefile了。现在Linux上的软件开发一般都是用autotools来制作Makefile。

   Autotools工具主要有:autoscan、aclocal、autoheader、autoconf、automake。使用autotools主要就是利用各个工具的脚本文件来生成最后的Makefile。各个工具的作用:
   (1)autoscan:它会在给定目录及其子目录树中检查源文件,若没有给出目录,就在当前目录及其子目录树中进行检查。它会扫描源代码以搜寻普通的可移植性问题,比如检查编译器,库,头文件等,生成configure.scan文件(并附带产生一个日志文件autoscan.log),它是configure.ac(或configure.in)的原型文件,而configure.ac是autoconf的脚本配置文件。
   过程:源代码文件-->autoscan-->configure.scan-->configure.ac(或configure.in)
   (2)aclocal: 根据已经安装的宏,用户定义的宏和acinclude.m4文件(如果有的话)中的宏,将configure.in(或configure.ac)文件所需要的宏集中地定义到文件aclocal.m4中。aclocal是一个perl脚本程序。之所以要创建aclocal.m4文件,是因为automake包含一堆的autoconf宏,这些宏能够在你的软件包中使用,而automake在某些情况下实际上也需要其中的一些宏。这堆宏必须在你的aclocal.m4中定义,否则他们将不会被autoconf看到。aclocal程序将会基于configure.in的内容自动产生aclocal.m4。
   过程:configure.ac、acinclude.m4(可选)、用户宏文件(可选)-->aclocal-->aclocal.m4
   (3)autoheader:通过扫描configure.ac(或configure.in),根据其中的某些宏(比如cpp宏定义)产生宏定义的模板文件config.h.in,configure脚本可以用这个文件生成一个由"#define"语句构成的宏定义文件config.h。
   当我们的程序要使用一些与平台相关的库时,由于在不同的平台上同样功能的库名字、函数、头文件的不同等,为了使程序具有可移植性,我们经常会在程序中使用一大堆的#ifdef或#ifndef预编译指令,这样非常地不方便。而autoheader就是解决这个问题的,在它生成的模板文件config.h.in中,为这些库、函数、头文件等定义了#undef宏标志,configure脚本把它转换成config.h后,就会变成#define宏标志,用作这些库、函数、头文件的保护符。这样,你可以在程序里包含这个config.h,然后使用其中的某些定义好的常量。
   过程:configure.ac、aclocal.m4(可选)-->autoheader-->config.h.in
   (4)autoconf:将configure.ac中的宏展开,生成configure脚本文件。这个过程可能要用到aclocal.m4中定义的宏。
   过程:configure.ac、aclocal.m4(可选)、config.h.in(可选)-->autoconf-->configure
   (5)automake(-a):选要自己写一个Makefile.am文件,然后automake根据configure.ac和Makefile.am中定义的结构,生成Makefile.in文件。如果在configure.ac中定义了一些特殊的宏,比如AC_PROG_LIBTOOL,它会调用libtoolize并产生config.guess、config.sub、ltmain.sh等文件。
   automake提供了三种软件等级foreign、gnu和gnits,让用户选择采用,默认等级为gnu。使用gnu等级时,automake还要求你必须有一些额外的文件,它们是install-sh、missing、depcomp、INSTALL、NEWS、 README、AUTHORS、ChangeLog、COPYING共9个文件,它们是一个符合GNU规范的代码文件结构所必须的文件。automake可以通过附加--add-missing参数(或-a)自动生成其中的一些文件(install-sh、missing、depcomp、INSTALL、COPYING),剩下的NEWS、README、AUTHORS、ChangeLog要自己创建。
   config.guess:GNU构建系统区分三类机器,运行构建用的编译器的“构建”机器、运行构建的软件包的“主机”机器、编译器用来产生代码的“目标”机器。这个脚本用来猜测“构建”机器的类型,并输出脚本所运行的系统的配置名(configure name)。
   config.sub:使配置名规范化。
   过程:Makefile.am、configure.ac-->automake(-a)-->Makefile.in、install-sh、missing、depcomp、INSTALL、COPYING。若调用了libtoolize,则另外产生的还有config.guess、config.sub、ltmain.sh等。
   (6)用./configure生成Makefile文件。configure脚本会收集系统的信息,创建config.status(这个文件可用来重新创建configure脚本),使用Makefile.in来创建Makefile文件,使用config.h.in(如果有的话)来创建config.h文件,并生成一个日志文件config.log(记录一些创建时的调试信息等),ltmain.sh会产生libtool文件,有时还会产生文件config.cache,stamp-h1(config.h的时间戳文件)等。这样就完成了Makefile文件的制作,并且常常具有以下的功能:make、make install、make uninstall、make clean、make distclean、make dist。
   使用configure命令时,用户可以对其进行方便地配置。./configure的自定义参数有两种,一种是开关式(--enable-XXX或--disable-XXX),另一种是开放式,即后面要填入一串字符(--with-XXX=yyyy)参数。
   制作完后,再查看config.h(如果存在的话),如果有必要,需要再改写源代码,并从第(1)步中的autoscan重新开始。

   libtool:提供一种标准的方法来创建静态库或共享库。它把特定于平台的库的产生过程的复杂性隐藏在一个统一的接口后面,这个接口通过libtool被所有的平台支持。
   过程:Makefile.in、config.h.in-->configure-->config.status、Makefile、config.h
   (7)make编译。现在就会根据Makefile文件中定义的目标和规则来编译整个源代码树,生成可执行的程序。常常还有文件mkinstalldirs(一般要自己编写)等。
   (8)make install(uninstall):把该程序安装到系统目录中去,make uninstall则卸载程序。
   (9)make dist:将所有的程序和相关的文档打包为一个.tar.gz压缩文件以供发布。
   (10)make clean(distclean):清除之前编译目标文件、的可执行文件及配置文件。而make distclean要清除所有生成的文件。  
   另外还有几个有用的工具在项目的构建过程中有时也会用到。
   autoupdate:更新configure.in文件,以适应更新版本的Autoconf。原来的configure.in会被备份下来。
   autoreconf:更新产生的配置文件(常在你更新了Autoconf工具的版本,或者安装了新版本的GNU构建系统时使用)。
   ifname:扫描C源程序文件(若没给定则使用标准输入),在标准输出上输出那些出现在#if,#elif,#ifdef或#ifndef中的标识符,每个标识符显示为一行,其后跟一空格和所属的文件名。

   下面用一个具体的实例来介绍整个构建流程。我们的项目有五个文件mytool1.h,mytool2.h,mytool1.c,mytool2.c,main.c。文件内容如下:

   构建流程如下:
   (1)运行autoscan。生成configure.scan和autoscan.log。操作结果如下:

   其中autoscan.log文件内容为空(一般常记录一些创建时的日志信息),configure.scan文件的内容如下:

   内容分析:
AC_PREREQ:声明本文件要求的autoconf版本,如本例使用的版本2.61,无需修改。
AC_INIT:用来定义软件的包名称、版本号、Bug报告地址,需要你自己填进去(名称可以随意起,只要符合标识符规则就行)。这里Bug报告地址BUG-REPORT-ADDRESS也可以省略,不省略时则一般填作者的e-mail。
AC_CONFIG_SRCDIR:用来侦测所指定的源码文件是否存在,来确定源码目录的有效性,在此处为当前目录下的mytool1.h。这个参数一般不需要修改。
AC_CONFIG_HEADER:用于生成config.h文件,以便autoheader使用。
AC_PROG_CC:表示测试程序用的语言,这里为C语言。而C++用AC_PROG_CXX,其他语言参考autoscan的手册。
AC_OUTPUT:指定要输出的Makefile文件名,注意是每个有源代码(或者有Makefile.am)的地方都要输出的Makefile文件,不同的文件之间用空格隔开,如AC_OUTPUT(Makefile src/Makefile)。也可用AC_CONFIG_FILES宏来指定Makefile文件,功能是一样的,多个Makefie文件(比如子目录中也有Makefile文件)时用空格分开。
   其他的一些这里没用到的宏定义主要有AC_PROG_INSTALL、PKG_CHECK_MODULES和AC_SUBST,AC_PROG_RANLIB(用到了库时要用这个宏)等,具体可参数帮助手册。中间的注释间可以添加分别用于测试程序、测试函数库、测试头文件等宏定义。
   (2)修改configure.scan并重命名为configure.ac(或configure.in也可),然后运行aclocal。为了使aclocal,autoheader,automake能使用这个文件(他们需要的文件名必须是configure.ac或configure.in),在修改时还要加入一些必要的宏,其中AM_INIT_AUTOMAKE(PACKAGE,VERSION)是automake必备的宏,参数的含义跟上面介绍的一样。另外当使用到库时,需要加入AC_PROG_RANLIB等。修改后的文件名为configure.ac,文件内容如下:

   这可能会有个疑问,为什么在(1)中autoscan不直接创建configure.ac,而是要创建为configure.scan后再让你来修改并重命名呢?当然,现在你也许不需要自己来写configure.ac,但是以后你可能会自己写。你当然不希望一不小心把configure.ac覆盖掉了。所以autoscan不会直接创建为configure.ac(或configure.in)。
   现在运行aclocal,根据configure.ac生成aclocal.m4文件。操作如下:

   产生了一个警告,是与acloal程序本身有关的,与我们的configure.ac无关,不管它了。可见同时也生成了一个缓存文件autom4te.cache。
   (3)运行autoheader。根据configure.ac产生config.h.in文件。注意configure.ac中必须要有AC_CONFIG_HEADER宏才能运行autoheader。操作如下:

   (4)运行autoconf,根据configure.ac、aclocal.m4和config.h.in生成configure脚本文件。操作如下:

   (5)运行automake,根据Makefile.am和configure.ac生成Makefile.in文件。先要编写Makefile.am文件,这很关键。Makefile.am编写如下:

   内容分析:
   AUTOMAKE_OPTIONS:设置automake的选项。automake提供了3种软件等级foreign、gnu、gnits让用户选择使用,默认等级是gnu。现在使用的gnu(由于是默认可以省略这一行),它会检测GNU规范需要的文件。
   bin_PROGRAMS:定义要产生的可执行程序名。如果要产生多个执行文件,每个文件名用空格隔开。
   mytool_SOURCES:定义mytool这个执行程序的依赖文件。_SOURCES前面的要与bin_PROGRAMS所定义的相一致。如果”mytool”这个程序是由多个原始文件所产生的,则必须把它所用到的所有原始文件都列出来,并用空格隔开。例目标体“mytool”要“main.c”、“mytool1.c”、“mytool1.h”、“mytool2.c”、“mytool2.h”五个依赖文件,则需要像上面那样定义。要注意的是,如果要定义多个执行文件,则对每个执行程序都要定义相应的XXX_SOURCES。
   其他的一些这里没用到的宏的介绍:
   SUBDIRS=src:如果执行程序依赖的文件不在同一个目录,有的在子目录中,这个宏用来指定子目录,相邻的子目录用空格分开。SUBDIRS里指定的每个子目录中都必须要有Makefile.am(相应地在configure.ac里也要把子目录中的Makefile文件名加入到AC_OUTPUT中)。要注意一点是bin_PROGRAMS定义的是一个可执行文件,也就是说后面的依赖文件列表中必须有一个是有main函数的。
   noinst_LIBRARIES=lib.a:要是我们的子目录中的代码不是一个独立的程序(没有main函数),只是拿来给其他目录的程序#include的怎么办?要用noinst_LIBRARIES来将它定义为库。之后和定义了bin_PROGRAMS一样定义XXX_SOURCES,例如根据上面noinst_LIBRARIES所定义的,我们可以这样来定义:lib_a_SOURCES=<文件列表>。
注意“.”要改成“_”,即lib.a在作为XXX_SOURCES的头部时变成了lib_a。 
   LDADD=sub/lib.a:最后哪里引用了这些代码,要加入相应地语句。比方说,我们的子目录名字为sub,在它的上层目录要引用到这些代码,那么要在它的上层目录中的Makefile.am中要加入这么一句来指定调用了sub子目录下的lib.a库(其实我们是把sub子目录下的代码编译成了一个库,库文件为lib.a,LDADD就是指定要调用哪个库)。注意别忘了使用库时,要给configure.ac中加入AC_PROG_RANLIB。
   总结一下Makefile.am是怎么放的:
   1. 根目录(configure.ac所在的目录)必须有一个Makefile.am
   2. 所有有需要编译的代码文件的目录下必须有一个Makefile.am
   3. 如果一个目录中有Makefile.am,那么必须在它的父目录中的Makefile.am里用SUBDIRS指定它。
   现在运行automake,由于使用了GNU构建等级,故我们先要自己创建NEWS、README、AUTHORS、ChangeLog文件,然后用带--add-missing选项的automake命令,操作如下:

   可见自动生成的另外5个GNU规范文件install-sh、missing、INSTALL、COPYING、depcomp。由于没有调用libtoolize,故没有产生config.guess、config.sub、ltmain.sh等文件。
   (6)运行./configure,根据Makefile.in和config.h.in生成config.status、Makefile、config.h、config.log文件,完成Makefile的制作。操作如下:

   可见configure脚本会收集系统的信息,创建config.status、Makefile、config.h、stamp-h1等文件。
   (7)运行make,编译全部源代码文件。操作如下:

   可见编译成功,生成了各个.o目标文件和最终的可执行程序mytool。
   (8)运行sudo make install,将程序安装到系统目录中,make uninstall卸载程序。如下:

   可见程序mytool安装成功,被安装在/usr/local/bin目录下,然后被卸载。
   (9)运行make dist,将程序打包为.tar.gz包,以便发布。如下:

   可见程序被打包为mytool-0.1.tar.gz,格式为“包名-版本号.tar.gz”。
   (10)运行make clean清除之前编译目标文件、可执行文件及配置文件,make distclean则清除所有生成的文件。如下:

   可见make clean清除之前编译目标文件、可执行文件及配置文件,make distclean还清除了config.status、Makefile、config.h等文件,回到./configure之前的状态。

   一切大功告成。由上面的叙述不难看出,autotools确实是软件维护与发布的便捷工具,也鉴于此,如今GUN的软件一般都是由automake来制作的。
   总结(项目的整个构建过程): autoscan、修改configure.scan并重命令为configure.ac、aclocal、autoheader、autoconf、编写Makefile.am并运行automake(-a)、./configure、make、make install/uninstall、make dist、make clean/distclean

  • 2
    点赞
  • 21
    收藏
    觉得还不错? 一键收藏
  • 4
    评论
评论 4
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值