目录
1 Autotools相关工具链
1.1 Autotools
1.2 其他相关工具
2 操作实例
2.1 安装autotools工具
2.2 准备源文件
2.3 生成configure.ac文件
2.4 生成aclocal.m4文件
2.5 生成config.h.in文件
2.6 生成Makefile.in文件
2.7 生成configure文件
2.8 生成Makefile文件
2.9 编译和测试
3 扩展
3.1 config.h中定义一个宏
3.2 运行configure命令
4 总结
我们经常从网上下载的源码,在其根目录有一个configure文件,直接执行configure文件,会产生一个makefile文件,再执行make就生成目标文件了。可是这个configure文件看着很复杂,其实它并不是手动编写的,那它是怎么来的呢,如果我们自己想发布一份源代码,需要怎么去生成configure呢
通过autotools生成makefile文件的流程图如下:
sudo apt install automake
源文件随便准备了两个,一个主程序文件,一个封装接口文件,目录结构如下:
configure-learn/
├── hello.c
├── hello.h
└── main.c
0 directories, 3 files
源文件创建后,我们就可以通过autoscan命令对该目录进行扫描,生成configure.scan文件。首先切换到该目录,然后执行命令如下:
autoscan
执行成功后可以看出多了两个文件,一个是autoscan.log,这个是日志文件;另外一个是configure.scan文件,这个是扫描的结果文件。
这里configure.scan其实是一个模板文件,我们需要手动修改其内容,并将其改名为configure.ac。具体需要做:
1) AC_INIT里面的参数: AC_INIT(main, 1.0.0, [email protected]);
2) 添加宏AM_INIT_AUTOMAKE;
3) 在AC_OUTPUT后添加输出文件Makefile。
修改前:
# -*- Autoconf -*-
# Process this file with autoconf to produce a configure script.
AC_PREREQ([2.69])
AC_INIT([FULL-PACKAGE-NAME], [VERSION], [BUG-REPORT-ADDRESS])
AC_CONFIG_SRCDIR([main.c])
AC_CONFIG_HEADERS([config.h])
# Checks for programs.
AC_PROG_CC
# Checks for libraries.
# Checks for header files.
# Checks for typedefs, structures, and compiler characteristics.
# Checks for library functions.
AC_OUTPUT
修改后:
# -*- Autoconf -*-
# Process this file with autoconf to produce a configure script.
AC_PREREQ([2.69])
AC_INIT(main, 1.0.0, [email protected])
AC_CONFIG_SRCDIR([main.c])
AC_CONFIG_HEADERS([config.h])
AM_INIT_AUTOMAKE(main, 1.0.0)
# Checks for programs.
AC_PROG_CC
# Checks for libraries.
# Checks for header files.
# Checks for typedefs, structures, and compiler characteristics.
# Checks for library functions.
AC_OUTPUT(Makefile)
下面给出本文件的简要说明(所有以”#”号开始的行为注释):
(1)AC_PREREQ
声明本文件要求的autoconf版本,本例使用的版本为2.69。
(2)AC_INIT
用来定义软件的名称和版本等信息,”FULL-PACKAGE-NAME”为软件包名称,”VERSION”为软件版本号,”BUG-REPORT-ADDRESS”为BUG报告地址(一般为软件作者邮件地址)。
(3)AC_CONFIG_SRCDIR
用来侦测所指定的源码文件是否存在,来确定源码目录的有效性。此处为当前目录下的hello.c。
(4)AC_CONFIG_HEADER
用于生成config.h文件,以便autoheader使用。
(5)AM_INIT_AUTOMAKE
检查automake尝试Makefile时的必要的工具。 例如:AM_INIT_AUTOMAKE([-Wall -Werror foreign subdir-objects]) , 一些可选的选项:
选项 解释
-Wall 打开全部警告
-Werror 将警告当错误处理
-foreign 放宽一些GNU标准需求
-1.11.1 需要automake的最低版本
-dist-bzip2 在使用make dist和make distcheck期间同时创建tar.bz2存档
-tar-ustar 使用ustar格式创建tar存档
(6)AC_PROG_CC
用来指定编译器,如果不指定,选用默认gcc。
(7)AC_OUTPUT
用来设定 configure 所要产生的文件,如果是makefile,configure会把它检查出来的结果带入makefile.in文件产生合适的makefile。使用Automake时,还需要一些其他的参数,这些额外的宏用aclocal工具产生。
(8)AC_DEFINE
格式: AC_DEFINE(VARIABLE, VALUE, DESCRIPTION)
输出宏定义到config.h中。
(9)AC_CHECK_HEADERS
格式:AC_CHECK_HEADERS(HEADERS…)
检查头HEADERS并且给每一个发现的头文件定义#define HAVE_HEADER_H
例如:AC_CHECK_HEADERS([unistd.h windows.h])
这个宏将在当前建造环境下检查unistd.h,windows.h是否存在。并将两个参数写入到配置头文件中。一般是config.h,你可以使用AC_CONFIG_HEADERS([headers])来指定。
AC_CONFIG_HEADERS([config.h])
如果存在就会出现在config.h中例如下面:
/* Define to 1 if you have the header file. */
#define HAVE_UNISTD_H 1
/* Define to 1 if you have the header file. */
#define HAVE_WINDOWS_H 1
(10) AC_CONFIG_FILES
格式:AC_CONFIG_FILES([Makefile sub/Makefile])
写入Makefile.am和sub/Makefile.am文件
(11) AC_CHECK_FUNC
格式: AC_CHECK_FUNCS (function…, [action-if-found], [action-if-not-found])
检查函数是否存在,如果存在执行动作action-if-found,没有发现执行动作action-if-not-found。
如果你没给出action-if-found和action-if-not-found,在发现函数的时候会定义对应的变量,以HAVE_开头,函数的名称都转换成大写。例如:
AC_CHECK_FUNCS(perror gettimeofday clock_gettime memset socket getifaddrs freeifaddrs fork)
如果发现clock_gettime将会定义变量 #define HAVE_CLOCK_GETTIME 1 在对应的配置头文件中。
如果没发现将不会定义。但是也会有一个注释行 /* #undef HAVE_CLOCK_GETTIME*/
(12)AC_ARG_WITH
格式: AC_ARG_WITH (package, help-string, [action-if-given], [action-if-not-given])
这个宏可以给configure增加 –with-package 这样模式的参数。很多软件都有可选项用来打开扩展功能,AC_ARG_WITH就是干这个的。它的第一参数给出扩展包的名称,出现在–with-后面。第二个参数给出一个参数说明,用在./configure –help中。[action-if-given]如果有该选项就被执行,[action-if-not-given]如果没有加这个选项就执行。
例如:
AC_ARG_WITH([militant],
[AS_HELP_STRING([--with-militant],
[Enable militant API assertions])],
[zmq_militant="yes"],
[])
if test "x$zmq_militant" = "xyes"; then
AC_DEFINE(ZMQ_ACT_MILITANT, 1, [Enable militant API assertions])
fi
AS_HELP_STRING([–with-militant],
[Enable militant API assertions])
定义一个帮助字串,将在configure –help中被显示出来。
它可以这么使用configure –with-militant,这导致zmq_militant=”yes”被执行,随后通过下面的if语句在config.h中定义一个宏 #define ZMQ_ACT_MILITANT 1。
(13) AC_ARG_ENABLE
格式:AC_ARG_ENABLE (feature, help-string, [action-if-given], [action-if-not-given])
这个宏可以为configure增加–enable-feature 或者 –disable-feature这样的选项。如果configure中加了给定的选项,就执行action-if-given,否则执行action-if-not-given。
AC_ARG_ENABLE([eventfd],
[AS_HELP_STRING([--disable-eventfd], [disable eventfd [default=no]])],
[zmq_enable_eventfd=$enableval],
[zmq_enable_eventfd=yes])
if test "x$zmq_enable_eventfd" = "xyes"; then
# Check if we have eventfd.h header file.
AC_CHECK_HEADERS(sys/eventfd.h,
[AC_DEFINE(ZMQ_HAVE_EVENTFD, 1, [Have eventfd extension.])])
fi
(14) 共享库和静态库
编译动态库或者静态库,你需要在你的configure.ac中加入下面的宏:
LT_PREREQ([2.4.0])
LT_INIT([disable-static win32-dll dlopen])
AC_PROG_LIBTOOL
LT_PREREQ给出一个版本需求检查。LT_INIT可以实现一些配置,例如win32-dll允许建造动态库,disable-static默认关闭静态库的建造。默认动态库和静态库是同时打开的。
AC_PROG_LIBTOOL检查libtool脚本。做完这些在你的configure中会增加一些选项–enable-static , –enable-shared。
细节参数可以看: libtool 官方文档
直接执行aclocal命令即可生成该文件:
aclocal
aclocal.m4是一个宏定义文件,该文件内容的生成依赖于configure.ac文件。aclocal会根据confgure.ac文件的内容,搜索本地的m4文件(通常在类似目录下面/usr/share/aclocal-1.15/),然后生成一个在本目录下面使用的aclocal.m4文件。
该文件的生成比较简单,直接在命令行执行如下命令即可:
autoheader
这个文件是一个模板文件,后面会利用该文件生成config.h文件。该文件包含一些宏定义。
生成Makefile.in文件之前需要手动创建一个 Makefile.am 文件,该文件用于描述源文件与目标文件的关系。本文对应的Makefile.am文件如下所示:
#AUTOMAKE_OPTIONS=foreign
bin_PROGRAMS=main
main_SOURCES=main.c hello.c hello.h
(1)AUTOMAKE_OPTIONS 设置Automake的选项。由于GNU对自己发布的软件有严格的规范,比如必须附带许可证声明文件COPYING等,否则Automake执行时会报错。Automake提供了3种软件等级:foreign、gnu和gnits,供用户选择,默认等级为gnu。本例使用foreign等级,它只检测必须的文件。
(2)bin_PROGRAMS 定义要产生的执行文件名。如果要产生多个执行文件,每个文件名用空格隔开。
(3)hello_SOURCES 定义”main”这个执行程序所需要的原始文件。如果”main”这个程序是由多个原始文件所产生的,则必须把它所用到的所有原始文件(包括头文件)都列出来,并用空格隔开。例如:若目标体”main”需要”main.c”、”hello.c”、”hello.h”两个依赖文件,则定义main_SOURCES=main.c hello.c hello.h。
可以看出该文件非常简单,这比写一个Makefile要简单的多。
运行下面命令生成Makefile.in:
automake --add-missing
加上–add-missing参数后,会补全缺少的脚本。
出现错误:
root@zl-src:~/vstdio-workspace/configure-project/configure-learn$ automake --add-missing
configure.ac:8: warning: AM_INIT_AUTOMAKE: two- and three-arguments forms are deprecated. For more info, see:
configure.ac:8: http://www.gnu.org/software/automake/manual/automake.html#Modernize-AM_005fINIT_005fAUTOMAKE-invocation
configure.ac:11: installing './compile'
configure.ac:8: installing './install-sh'
configure.ac:8: installing './missing'
Makefile.am: installing './INSTALL'
Makefile.am: error: required file './NEWS' not found
Makefile.am: error: required file './README' not found
Makefile.am: error: required file './AUTHORS' not found
Makefile.am: error: required file './ChangeLog' not found
Makefile.am: installing './COPYING' using GNU General Public License v3 file
Makefile.am: Consider adding the COPYING file to the version control system
Makefile.am: for your code, to avoid questions about which license your project uses
Makefile.am: installing './depcomp'
分析修改
因为上面Makefile.am文件里面将第一行AUTOMAKE_OPTIONS的设置屏蔽了,默认是gnu,而gnu有标准的软件发布规范,所以需要相应的文件,这里我们可以打开第一行的设置,更换规范检测配置,或者手动暂时创建需要的文件也行,下面是手动创建的方式,手动创建需要的文件,需要这几个文件,是正规软件发布需要的:
touch NEWS README AUTHORS ChangeLog
再次执行automake就可以成功生成Makefile.in文件了。如果要生成多个目标文件,需要在这里写多个源文件与目标文件的对应关系。这种情况是非常常见的,比如一些复杂的项目中通常会包含主程序,测试程序,动态库等等。
上述文件都生成后就可以生成configure文件了。该文件是用于生成Makefile的一个脚本。我们在很多开源项目中肯定都遇到过。在开源项目中通常都有一个生成好的configure文件,我们只需要执行该文件就可以生成Makefile。
生成configure文件的方法很简单,我们执行如下命令即可:
autoconf
至此我们完成了生成Makefile的所有准备工作。
在该目录下面运行configure脚本,即可生成Makefile文件。
./configure
root@zl-src:~/vstdio-workspace/configure-project/configure-learn$ ./configure
checking for a BSD-compatible install... /usr/bin/install -c
checking whether build environment is sane... yes
checking for a thread-safe mkdir -p... /bin/mkdir -p
checking for gawk... gawk
checking whether make sets $(MAKE)... yes
checking whether make supports nested variables... yes
checking for gcc... gcc
checking whether the C compiler works... yes
checking for C compiler default output file name... a.out
checking for suffix of executables...
checking whether we are cross compiling... no
checking for suffix of object files... o
checking whether we are using the GNU C compiler... yes
checking whether gcc accepts -g... yes
checking for gcc option to accept ISO C89... none needed
checking whether gcc understands -c and -o together... yes
checking for style of include used by make... GNU
checking dependency style of gcc... gcc3
checking that generated files are newer than configure... done
configure: creating ./config.status
config.status: creating Makefile
config.status: creating config.h
config.status: executing depfiles commands
直接执行make即可:
比如:在config.h中定义一个宏 HAVE_TEST为1
(1)修改configure.ac,添加如下代码:
AC_DEFINE([HAVE_TEST], [1],
[Define to 1 if you have the test function.])
(2)运行autoheader,重新生成config.h.in文件
(3)运行autoconf,重新生成configure文件
(4)重新运行 ./configure,更新config.h文件
直接在Ubuntu上运行的话,这样是可以的,但是实际开发中会涉及一些arm系统之类的,这个时候我们可能就需要设置一些参数。譬如enbale/disbale一些特性,设置交叉编译平台(例如–host=linux-mips),设置编译安装目录(例如–prefix=path_to_your_build_directory)具体可以查看help信息 。
需要项目维护者手动修改的文件除了可选的NEWS README AUTHORS ChangeLog文件之外,就是configure.ac文件和每个源码文件夹下的Makefile.am文件了。