对于较大项目来说,手工编写Makefile文件非常困难,一是Makefile文件的结构复杂,二是Makefile文件常常会受到开发环境的限制,只要环境参数不同或者更改了路径,就有可能需要修改该文件以适应环境的变化。Autotools是一个系列工具,它可以自动生成Makefile文件,对较大项目的开发提供了有力的支持。Autotools主要包含以下工具:autoscan: 在自动生成Makefile过程中,需要使用该工具生成configure.scan文件,对该文件进行必要的修改,比如加一些需要的信息或修改一些信息为下面完成自动生成Makefile做准备。然后改名为configure.ac或者configure.in。aclocal:这是一个perl脚本程序,通过扫描configure.ac文件(或configure.in)产生aclocal.m4文件。aclocal.m4文件的内容主要是本地定义的宏。autoconf: 一个shell脚本工具,用来自动配置软件源代码以适应多种类似POSIX的系统。configure.in是autoconf的脚本配置文件,它的原型文件是configure.scan,由autoscan生成。autoheader: 生成config.h.in文件。该工具通常从acconfig.h文件中复制用户附加的符号定义。automake: 从脚本配置文件Makefile.am自动生成Makefile.in的工具,configure程序使用Makefile.in生成Makefilelibtool: 方便生成各种程序库的工具图1是生成Makefile文件的流程图。下面按图1 所示步骤举例说明Makefile文件的自动产生过程。
1. 项目说明首先建立一个目录ts,用来存放项目文件。在ts下建立一个src目录,一般来说源代码都放在src中(这是一个不成文的规定),在src目录下编写3个源程序,整体结构如下:
|-|-teacher.c|-student.c|-ts.h
这三个源程序代码如下:
// ts.h#ifndef __STU__#define __STU__void student(void);#endif
#include #include #ifdef HAVE_CONFIG_H#include #endifint main(void){ printf("Teacher: I'm Mr. Bobo.\n"); printf("Teacher: Please tell me your names!\n"); student(); #ifdef HELLO printf("Teacher: Hey Taotao, long time no see.\n"); #endif}
// student.c#include #ifdef HAVE_CONFIG_H#include #endifvoid student(void){ #ifdef HELLO printf("Student: Hello, Mr. Bobo.\n"); #endif printf("Student: My name is Taotao.\n");}
功能:
1)Bobo老师点名。
2)如果定义了HELLO,学生会向老师问好,然后报出自己的名字。Bobo老师也会向学生问好。
3)如果没有定义HELLO,学生仅报出自己的名字,Bobo老师点名结束。
显然程序编译运行的结果与HELLO这个宏是否定义有关,我们只要在编译前决定要不要定义它,就能实现不同的效果。
注:如果config.h存在的话,编译时Makefile会把宏HAVE_CONFIG_H传给编译器,如果没有定义HAVE_CONFIG_H的话,编译时不应该把config.h 包含进去。
2. 自动生成Makefile过程首先建立一个目录ts,用来存放项目文件。在ts下建立一个src目录,一般来说源代码都放在src中(这是一个不成文的规定),在src目录下编写3个源程序,整体结构如下:
第一步:确认系统是否安装Autotools工具。
如果没有安装那就先安装,本文在CentOS 7环境下完成。检查autotools工具是否安装可以使用which命令。
本机没有安装autotools工具,现在使用命令yum -y install autoconf automake安装,如下图所示。
第二步:生成configure.in文件。
生成configure.in文件的方法有两个,一个是自己从零开始编写,二是用autoscan产生。在ts目录下执行autoscan后会生成configure.scan文件,其中包含了一些模板内容,使用时只要把名字改成configure.in就可以。
autoscan 还会产生一个 autoscan.log 档案以记录 autoscan 的扫瞄过程。这个档案可以放心地删除。
修改configure.in文件,内容如下。
图中划线的行是修改或增加的行。
AC_PREREQ(2.69) 确保使用的是足够新的Autoconf版本。如果用于创建configure的Autoconf的版本比version 要早,就在标准错误输出打印一条错误消息并不会创建configure。
AC_INIT 定义软件的基本信息,包括设置包的全称,版本号以及报告BUG时需要用的邮箱地址。
AC_CONFIG_SRCDIR用来侦测所指定的源码文件是否存在,来确定源码目录的有效性。
AC_CONFIG_HEADER用于生成config.h文件,以便autoheader使用 。
AC_ARG_ENABLE定义一个命令行选项,格式是:
AC_ARG_ENABLE (feature,
help-string
[, action-if-given
[, action-if-not-given]])
例,如果定义选项--enble-hello, AC_ARG_ENABLE中的参数分别为:feature为hello;提示信息help-string可以为[ --enable-hello Hello is present];action-if-given为空,即有该选项时enable_hello取默认值,即yes;action-if-not-given为enable_hello=no,即无该选项时enable_hello的值为no。
AC_DEFINE:定义宏。
AM_INIT_AUTOMAKE初始化automake。传到这个宏里的参数是要编译的应用程序的名称和版本号。
AC_OUTPUT: 设置configure所要产生的文件,若是Makefile,configure 便会把它检查出来的结果带入Makefile.in文件后产生合适的Makefile。
注意:configure.in中使用的宏有两种,一种是以AC开头,表示由autoconf 提供,另一种是以AM开头,代表由automake提供。
第三步:运行aclocal。
在ts录下运行aclocal,将会生成aclocal.m4文件和autom4te.cache目录。
第四步:编写acconfig.h在configure.in中使用到的宏(Macro),都应该在这个文件声明,一般用#undef来声明。acconfig.h源程序如下:
#undef HELLO
即未定义HELLO第五步:运行autoheaderautoheader会根据configure.in、acconfig.h生成config.h.in文件。第六步:编写Makefile.am一般来说,在顶级目录和各子目录都应有一个Makefile.am。 本例内容为:
第一行是告诉automake不要检测目录中是否存在AUTHORS、README等文件。第二行是告诉automake处理src这个子目录。 automake提供了三种软件等级:foreign、gnu和gnits,让用户选择采用,默认等级为gnu。在本例使用foreign等级,它只检测必须的文件。定义要产生的执行文件名。如果要产生多个执行文件,每个文件名用空格隔开。src目录下的Makefile.am文件内容为:
第一行作用同前。第二行是目标执行程序的名称。第三行是生成ts这个执行文件所需的源程序和头文件名称。
第七步:运行automake接着执行automake,在命令行下输入automake -a自动执行。
第八步:运行autoconf执行autoconf将会生成最终的configure。
3. 测试(1) 无选项--enable-hello
注:部分截图
(2)有选项--enable-hello4. tar包好了,至此为止,我们的小软件已经测试完毕,可以发布了,在ts下有很多文件,有的是我们自己写的,也有些是编译时生成的临时档案,到底哪些需要打包到发行包中呢?当然你可以自己一个一个文件挑选,但Autotools工具给我们提供了几个极其方便的功能让我们打包。我们可以用make dist或make distcheck来生成相应的tar包,其中后者还会帮我们测试发布包能否正常工作,所以推荐使用make distcheck。
看到了吧?发布包ts-1.0.tar.gz已经放到ts下了,有没有留意,这里用的软件名及版本号正是 configure.in中AM_INIT_AUTOMAKE所带的两个参数!现在你可以试试把它解压安装了.