autotools工具集

autotools工具集

autotools

原文地址:https://gitee.com/simpost/autotools_tutorial

一、简介

1.1 介绍

我们知道在Linux下编译一个比较大型的项目,我们可以通过Makefile的方式来完成。但是,Makefile拥有复杂的语法结构,甚至让人难以领会,当我们项目非常大的时候,维护Makefile会成为一件非常头疼的事。Autotools工具就是专门用来生成Makefile的,这个工具让让我们很大程度上降低了开发的难道。

Autotools并不是一个工具,而是一系列工具:

autoscan

aclocal

autoconf

autoheader

automake

这一系列工具看着复杂,但我们只要记住:最终目标是生成Makefile。

一般情况下系统会默认安装这一系列工具,若未安装,在CentOS中可以使用下面命令安装:

sudo yum install automake

有关Autotools的详细完整的介绍,详见官网:https://www.lrde.epita.fr/~adl/autotools.html

1.2 不同视角的程序构建

1.2.1 用户视角

一般过程是configure,make,make install三部曲。这种方式成为一种习惯,被广泛使用。

在上图中,开发者在分发源码包时,除了源代码中的头文件(.h)和程序源文件(.c),还有许多支持软件构建的文件和工具。最重要的就是Makefile.in和config.h。

configure脚本执行时,将为每一个.in文件处理成对应的非.in文件,即生成:Makefile,src/Makefile,config.h 。大部分情况下,只有Makefile和config.h。Makefile用于被make程序识别并构建软件,而config.h中定义的宏,有助于软件通过预编译来改变自身代码,来适应目标平台某些特殊性。

有些软件在configure阶段,还可以生成其他文件,这完全取决于软件本身。

1.2.2 开发者视角

开发者除了编写软件本身的代码外,还需要负责生成构建软件所需要的文件和工具。因此对于开发者而言,要么自己编写构建用的脚本,要么选择部分依赖工具。Autotools就是这样的工具。Autotools包括了autoconf和automake等命令。

autoreconf命令

为了生成configure脚本和Makefile.in等文件,开发者需要创建并维护一个configure.ac文件,以及一些列的Makefile.am。autoreconf程序能够自动按照合理的顺序调用autoconf、automake、aclocal程序

configure.ac文件

configure.ac用于生成configure脚本,autoconf工具用来完成这一步。下面是一个简单的configure.ac例子:

AC_PREREQ

AC_PREREQ([2.63])

AC_INIT([st], [1.0], [zhoupingtkbjb@163.com])

AC_CONFIG_SRCDIR([src/main.c])

AC_CONFIG_HEADERS([src/config.h])

AM_INIT_AUTOMAKE([foreign])

# Checks for programs.

AC_PROG_CC

AC_PROG_LIBTOOL

# Checks for libraries.

# Checks for header files.

# Checks for typedefs, structures, and compiler characteristics.

# Checks for library functions.

AC_CONFIG_FILES([Makefile

src/Makefile

src/a/Makefile

src/b/Makefile])

AC_OUTPUT

其中以AC_开头的类似函数调用一样的代码,实际上时被称为“宏”的调用。这里的宏,与C语言中的宏概念类似,会被替换展开。configure.ac文件的一般布局是:

AC_INIT

测试程序

测试函数库

测试头文件

测试类型定义

测试结构

测试编译器特性

测试库函数

测试系统调用

AC_OUTPUT

m4是一个经典的宏工具。autoconf正是构建在m4之上,可以理解为autoconf预先定义了大量的、用户检查系统可移植性的宏,这些宏在展开就是大量的shell脚本。所以编写configure.ac就需要对这些宏掌握熟练,并且合理调用。

autoscan和configure.scan

通过调用autoscan命令,得到一个初始化的configure.scan文件。然后重命名为configure.ac后,在此基础上编辑configure.ac。

autoscan会扫描源码,并生成一些通用的宏调用,输入的声明,以及输出的声明。尽管autoscan十分方便,但是没人能够在构建之前,就把源码完全写好。因此,autoscan通常用于初始化configure.ac,即生成configure.ac的雏形文件configure.scan。

autoheader和configure.h

autoheader命令扫描configure.ac文件,并确定如何生成config.h.in。每当configure.ac变化时,都可以通过执行autoheader更新config.h.in。

在configure.ac通过AC_CONFIG_HEADERS([config.h])告诉autoheader应当生成config.h.in的路径。config.h包含了大量的宏定义,其中包括软件包的名字等信息,程序可以直接使用这些宏。更重要的是,程序可以根据其中的对目标平台的可移植相关的宏,通过条件编译,动态的调整编译行为。

automake和Makefile.am

手工编写Makefile是一件相当繁琐的事情,并且随着项目的复杂程序变大,编写难度越来越大。automake工具应运而生。可以编辑Makefile.am文件,并依靠automake来生成Makefile.in。

aclocal

configure.ac实际是依靠宏展开来得到configure。因此,能否成功生成,取决于宏定义是否能够找打。

autoconf会从自身安装路径下寻找事先定义好的宏。然而对于像automake、libtool、gettex等第三方扩展宏,autoconf便无从知晓。

因此,aclocal将在configure.ac同一个目录下生成aclocal.m4,在扫描configure.ac过程中,将第三方扩展和开发者自己编写的宏定义复制进去。

如此一来,autoconf遇到不认识的宏时,就会从aclocal.m4中查找。

上述命令与不同文件之间的关系如下图所示:

二、流程与规则

2.1 Autotools运行流程

执行autoscan命令,扫描工作目录并生成configure.scan文件;

修改configure.scan为configure.ac文件,并修改配置内容;

执行aclocal命令,扫描configure.ac文件并生成aclocal.m4文件;

执行autoconf命令,将configure.ac文件中的宏展开,生成configure脚本;

执行autoheader命令,生成config.h.in文件;

创建Makefile.am文件,修改配置内容;

执行automake --add-missing命令,生成Makefile.in文件;

执行./configure命令,生成Makefile文件;

执行make命令,生成需要的库或可执行程序;

执行make install/uninstall进行安装和卸载;

执行make dist对软件进行打包工作。

若是开发过程中,修改了部分文件(configure.ac、各目录的Makefile.am等),可以使用简化的autoreconf命令,它将自动按照合理的顺序调用aclocal、autoconf、automake命令。

2.2 configure.ac标签说明

标签说明

AC_PREREQ

声明autoconf要求的版本号

AC_INIT

定义软件名称、版本号、联系方式

AM_INIT_AUTOMAKE

必须要的,参数为软件名称和版本号

AC_CONFIG_SRCDIR

用来侦测所指定的源文件是否存在,来确定源码目录的有效性

AC_CONFIG_HEADERS

用于生成config.h文件,以便autoheader命令使用

AC_PROG_CC

指定编译器,默认为CC

AC_CHECK_HEADERS

autoscan侦测到的头文件

AC_CONFIG_FILES

生成相应的Makefile文件,不同文件夹下的Makefile通过空格分隔

AC_OUTPUT

指定configure所要产生的文件,如果是makefile,configure会把它检查出来的结果带入makefile.in文件产生合适的makefile

2.3 Makefile.am解读

2.3.1 可执行文件类型

规则说明

bin_PROGRAMS

指定生成可执行文件的名称,如果可执行文件为多个,则可以通过空格方式分割;当运行make install命令时,会被默认安装到/usr/local/bin目录下。

noinst_PROGRAMS

指定生成可执行文件的名称,如果可执行文件为多个,则可以通过空格方式分割;当运行make install命令时,不会被安装。

hello_SOURCES

编译可执行文件hello所依赖的*.c源文件,多个文件之间用空格分割。

hello_LDADD

编译可执行文件hello所依赖的*.so和*.a的库文件。

hello_CPPFLAGS

编译可执行文件hello所需要的编译选项。

hello_LDFLAGS

链接可执行文件时所需要的链接选项。

2.3.2 库文件类型

库文件类型,一般会将C源码放在不同的文件夹中,并且每个文件夹中都会有各自的Makefile.am文件,并且会被编译成动态库*.so或者静态库*.a格式的库文件。

如果使用静态库,只需要在configure.ac中加入AC_PROG_RANLIB定义;如果生成动态库,则使用AC_PROG_LIBTOOL。

规则说明

lib_LIBRARIES

指定生成静态库或动态库文件的名称,当运行make install命令时,会被默认安装到/usr/local/lib目录下。

noinst_LIBRARIES

指定生成静态库或动态库文件的名称,当运行make install命令时,不会被安装。

libsrc_a_SOURCES

编译libsrc.a/so库所依赖的*.c源文件,多个文件之间用空格分隔。

libsrc_a_LDADD

加载libsrc.a/so库时所依赖的库文件。

libsrc_a_CPPFLAGS

编译libsrc.a/so库所需要的编译选项。

libsrc_a_LDFLAGS

链接libsrc.a/so库文件时所需要的链接选项。

2.3.3 头文件

我们一般需要导入一些*.h的头文件,如果在Makefile.am中没有标识需要导入的头文件,那么在make dist打包的时候会出现头文件不被打包的问题。因此,建议都加上头文件标识。

include_HEADERS = xxx.h xxx.h xxx.h

在make install时,头文件默认会被安装到linux系统的/usr/local/include目录。

2.3.4 数据文件

data_DATA = data1, data2

2.3.5 常用变量

变量含义

INCLUDES

编译所需要的头文件

LDADD

链接时需要的库文件

LDFLAGS

连接时所需要的链接选项

SUBDIRS

处理本目录之前,先递归处理的子目录

EXTRA_DIST

源程序和一些默认的文件将自动打包入.tar.gz包,其他文件需要进入.tar.gz包可以使用这个变量指定,比如配置文件、数据文件等等

AM_V_AR

用于指定把目标文件打包成静态库时使用的ar命令

RANLIB

用于指定为静态库创建索引的ranlib命令

3.3.6 路径变量

在Makefile.am中尽量使用相对路径,系统预定义了两个基本路径:

$(top_srcdir):工程最顶层目录,用于引用源程序;

$(top_builddir):定义了生成目标文件最上层目录,用于引用.o等编译的中间文件。

3.3.7 安装目录

默认情况下,执行make install命令会将文件安装到/usr/local/bin、/usr/local/include、/usr/local/lib目录下面。我们可以通过./configure --prefix=指定安装路径。

我们也可以修改下面变量,指定安装的路径:

bindir = $(prefix)/bin

libdir = $(prefix)/bin

datadir = $(prefix)/share

sysconfdir = $(prefix)/etc

includedir = $(prefix)/include

三、使用实例

3.1 C源码在同一目录

如果你的C源文件放在同一个目录下面,那么使用Autotools的时候会相对简单很多。比较著名的开源软件Memcache也是放在同一目录下的。

3.1.1 源代码讲解

主程序main.c

#include

#include

#include

#include "sum.h"

#include "get.h"

int main(void)

{

int x = 10;

int y = 20;

int z = sum(x, y);

puts("This is main");

printf("Z:%d\n", z);

x = 20;

z = get(x, y);

printf("Z:%d\n", z);

return 0;

}

sum.c和sum.h

/* sum.h */

extern int sum(int x, int y);

/* sum.c */

#include

#include

#include "val.h"

int sum(int x, int y)

{

val(x);

printf("This is sum method!\n");

return (x + y);

}

val.c和val.h

/* val.h */

extern int val(int x);

/* val.c */

#include

int val(int x)

{

printf("This is val method, X:%d\n", x);

return x;

}

get.c和get.h

/* get.h */

extern int get(int x, int y);

/* get.c */

#include

int get(int x, int y)

{

printf("This is get method\n");

return (x*y);

}

目录文件结构如下:

$ ls

get.c get.h main.c sum.c sum.h val.c val.h

3.1.2 autoscan命令

第一步,我们使用autoscan命令扫描工作目录,并生成configure.scan文件,并将其重新命名为configure.ac。

$ autoscan

$ ls

autoscan.log configure.scan get.c get.h main.c sum.c sum.h val.c val.h

$ mv configure.scan configure.ac

$ cat configure.ac

# -*- 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([sum.h])

AC_CONFIG_HEADERS([config.h])

# Checks for programs.

AC_PROG_CC

# Checks for libraries.

# Checks for header files.

AC_CHECK_HEADERS([stdlib.h unistd.h])

# Checks for typedefs, structures, and compiler characteristics.

# Checks for library functions.

AC_OUTPUT

接着我们编辑configure.ac文件,将其修改为:

# -*- Autoconf -*-

# Process this file with autoconf to produce a configure script.

AC_PREREQ([2.69])

AC_INIT([hello], [1.0], [konishi5202@163.com])

AM_INIT_AUTOMAKE(hello, 1.0)

AC_CONFIG_SRCDIR([main.c])

AC_CONFIG_HEADERS([config.h])

# Checks for programs.

AC_PROG_CC

# Checks for libraries.

# Checks for header files.

AC_CHECK_HEADERS([stdlib.h unistd.h])

# Checks for typedefs, structures, and compiler characteristics.

# Checks for library functions.

AC_CONFIG_FILES([Makefile])

AC_OUTPUT

3.1.3 aclocal命令

第二步,执行aclocal命令,扫描configure.ac文件生成aclocal.m4文件,该文件主要处理本地的宏定义,它根据已经安装的宏、用户定义宏和acinclude.m4文件中的宏,将configure.ac文件需要的宏集中定义到文件aclocal.m4中。

$ ls

autoscan.log configure.ac get.c get.h main.c sum.c sum.h val.c val.h

$ aclocal

$ ls

aclocal.m4 autom4te.cache autoscan.log configure.ac get.c get.h main.c sum.c sum.h val.c val.h

3.1.4 autoconf命令

第三步,执行autoconf命令,将configure.ac文件中的宏展开,生成configure脚本,这个过程需要用到第二步生成的aclocal.m4中定义的宏。

$ ls

aclocal.m4 autom4te.cache autoscan.log configure.ac get.c get.h main.c sum.c sum.h val.c val.h

$ autoconf

$ ls

aclocal.m4 autom4te.cache autoscan.log configure configure.ac get.c get.h main.c sum.c sum.h val.c val.h

3.1.5 autoheader命令

第四步,执行autoheader命令,生成config.h.in文件。该命令通常会从acconfig.h文件中复制用户附加的符号定义。本例中没有附加的符号定义,所以不需要创建acconfig.h文件。

$ ls

aclocal.m4 autom4te.cache autoscan.log configure configure.ac get.c get.h main.c sum.c sum.h val.c val.h

$ autoheader

$ ls

aclocal.m4 autom4te.cache autoscan.log config.h.in configure configure.ac get.c get.h main.c sum.c sum.h val.c val.h

3.1.6 创建Makefile.am文件

第五步,创建Makefile.am文件,aotumake工具会根据configure.in中的参量把Makefile.am转换成Makefile.in文件,最终通过Makefile.in生成Makefile文件。所以Makefile.am文件非常重要,它定义了一些生成Makefile的规则。

$ vim Makefile.am

$ cat Makefile.am

AUTOMAKE_OPTIONS = foreign

bin_PROGRAMS = hello

hello_SOURCES = main.c val.h val.c get.h get.c sum.h sum.c

3.1.7 automake命令

第六步,执行automake --add-missing命令,生成Makefile.in文件。选型‘--add-missing’可以让automake自动添加一些必须的脚本文件,如果发现一些文件不存在,可以通过手工touch创建:

$ automake --add-missing

configure.ac:6: warning: AM_INIT_AUTOMAKE: two- and three-arguments forms are deprecated. For more info, see:

configure.ac:6: http://www.gnu.org/software/automake/manual/automake.html#Modernize-AM_005fINIT_005fAUTOMAKE-invocation

configure.ac:6: installing './install-sh'

configure.ac:6: 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'

$ touch NEWS README AUTHORS ChangeLog

$ automake --add-missing

configure.ac:6: warning: AM_INIT_AUTOMAKE: two- and three-arguments forms are deprecated. For more info, see:

configure.ac:6: http://www.gnu.org/software/automake/manual/automake.html#Modernize-AM_005fINIT_005fAUTOMAKE-invocation

$ ls

aclocal.m4 autom4te.cache ChangeLog configure COPYING get.c INSTALL main.c Makefile.in NEWS sum.c val.c

AUTHORS autoscan.log config.h.in configure.ac depcomp get.h install-sh Makefile.am missing README sum.h val.h

3.1.8 软件三部曲

接下来,就是大家非常熟悉的三部曲了:configure、make、make install。

configure主要把Makefile.in变成最终的Makefile文件,同时configure会把一些配置参数配置到Makefile文件里面。

configure命令执行结果,生成Makefile文件:

$ ./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... /usr/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 for style of include used by make... GNU

checking dependency style of gcc... gcc3

checking how to run the C preprocessor... gcc -E

checking for grep that handles long lines and -e... /usr/bin/grep

checking for egrep... /usr/bin/grep -E

checking for ANSI C header files... yes

checking for sys/types.h... yes

checking for sys/stat.h... yes

checking for stdlib.h... yes

checking for string.h... yes

checking for memory.h... yes

checking for strings.h... yes

checking for inttypes.h... yes

checking for stdint.h... yes

checking for unistd.h... yes

checking for stdlib.h... (cached) yes

checking for unistd.h... (cached) yes

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命令执行结果,生成hello可执行程序:

$ make

make all-am

make[1]: Entering directory `/work/study/Module/autotools/test_c2'

gcc -DHAVE_CONFIG_H -I. -g -O2 -MT main.o -MD -MP -MF .deps/main.Tpo -c -o main.o main.c

mv -f .deps/main.Tpo .deps/main.Po

gcc -DHAVE_CONFIG_H -I. -g -O2 -MT val.o -MD -MP -MF .deps/val.Tpo -c -o val.o val.c

mv -f .deps/val.Tpo .deps/val.Po

gcc -DHAVE_CONFIG_H -I. -g -O2 -MT get.o -MD -MP -MF .deps/get.Tpo -c -o get.o get.c

mv -f .deps/get.Tpo .deps/get.Po

gcc -DHAVE_CONFIG_H -I. -g -O2 -MT sum.o -MD -MP -MF .deps/sum.Tpo -c -o sum.o sum.c

mv -f .deps/sum.Tpo .deps/sum.Po

gcc -g -O2 -o hello main.o val.o get.o sum.o

make[1]: Leaving directory `/work/study/Module/autotools/test_c2'

执行可执行程序hello:

$ ./hello

This is val method, X:10

This is sum method!

This is main

Z:30

This is get method

Z:400

3.1.9 软件打包发布

执行make dist命令可以对软件进行打包:

$ make dist

make dist-gzip am__post_remove_distdir='@:'

make[1]: Entering directory `/work/study/Module/autotools/test_c2'

if test -d "hello-1.0"; then find "hello-1.0" -type d ! -perm -200 -exec chmod u+w {} ';' && rm -rf "hello-1.0" || { sleep 5 && rm -rf "hello-1.0"; }; else :; fi

test -d "hello-1.0" || mkdir "hello-1.0"

test -n "" \

|| find "hello-1.0" -type d ! -perm -755 \

-exec chmod u+rwx,go+rx {} \; -o \

! -type d ! -perm -444 -links 1 -exec chmod a+r {} \; -o \

! -type d ! -perm -400 -exec chmod a+r {} \; -o \

! -type d ! -perm -444 -exec /bin/sh /work/study/Module/autotools/test_c2/install-sh -c -m a+r {} {} \; \

|| chmod -R a+r "hello-1.0"

tardir=hello-1.0 && ${TAR-tar} chof - "$tardir" | GZIP=--best gzip -c >hello-1.0.tar.gz

make[1]: Leaving directory `/work/study/Module/autotools/test_c2'

if test -d "hello-1.0"; then find "hello-1.0" -type d ! -perm -200 -exec chmod u+w {} ';' && rm -rf "hello-1.0" || { sleep 5 && rm -rf "hello-1.0"; }; else :; fi

$ ls

aclocal.m4 ChangeLog config.status depcomp hello main.c Makefile.in stamp-h1 val.c

AUTHORS config.h configure get.c hello-1.0.tar.gz main.o missing sum.c val.h

autom4te.cache config.h.in configure.ac get.h INSTALL Makefile NEWS sum.h val.o

autoscan.log config.log COPYING get.o install-sh Makefile.am README sum.o

注意上面的hello-1.0.tar.gz文件即是打包发布的文件。使用发布文件的方法如下:

下载hello-1.0.tar.gz压缩包;

使用tar -zxvf hello-1.0.tar.gz命令解压;

使用./configure命令生成Makefile文件;

使用make命令编译源代码文件生成可执行程序;

使用make install或make uninstall来安装或卸载软件。

3.2 C源码在不同目录

如果你的入口文件main.c和依赖的文件不是在同一个目录中的,使用Autotools来管理项目的时候会稍微复杂一下。

在不同的目录下,项目会生成*.a文件的静态连接(静态连接相当于将多个.o目标文件合成一个),最外层的main.c会通过静态连接方式来实现连接。

3.2.1 源代码讲解

基于前面小节的源代码,这里还会加入math数学库的使用,让例子稍显复杂来介绍不同目录下的Autotools的使用。

我们首先创建include和source目录,并把相应的文件放进去:

$ ls

include main.c source

$ ls include/

get.h sum.h val.h

$ ls source/

get.c sum.c val.c

修改main.c文件,添加调用math的abs函数:

#include

#include

#include

#include

#include "sum.h"

#include "get.h"

int main(void)

{

int x = 10;

int y = 20;

int z = sum(x, y);

puts("This is main");

printf("Z:%d\n", z);

x = 20;

z = get(x, y);

printf("Z:%d\n", z);

z = abs(-3);

printf("Z:%d\n", z);

return 0;

}

其他源代码文件均不做修改。

3.2.2 autoscan命令

第一步,使用autoscan命令扫描工作目录,并生成configure.scan文件,并将其重新命名为configure.ac:

$ autoscan

$ ls

autoscan.log configure.scan include main.c source

$ mv configure.scan configure.ac

$ cat configure.ac

# -*- 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.

AC_CHECK_HEADERS([stdlib.h unistd.h])

# Checks for typedefs, structures, and compiler characteristics.

# Checks for library functions.

AC_OUTPUT

将其修改为:

$ vim configure.ac

[study@konishi test_c3]$ cat configure.ac

# -*- Autoconf -*-

# Process this file with autoconf to produce a configure script.

AC_PREREQ([2.69])

AC_INIT([hello], [1.0], [konishi5202@163.com])

AM_INIT_AUTOMAKE(hello, 1.0)

AC_CONFIG_SRCDIR([main.c])

AC_CONFIG_HEADERS([config.h])

# Generate static lib

AC_PROG_RANLIB

# Checks for programs.

AC_PROG_CC

# Checks for libraries.

# Checks for header files.

AC_CHECK_HEADERS([stdlib.h unistd.h])

# Checks for typedefs, structures, and compiler characteristics.

# Checks for library functions.

AC_CONFIG_FILES([Makefile

source/Makefile])

AC_OUTPUT

3.2.3 aclocal命令

第二步,执行aclocal命令,扫描configure.ac文件生成aclocal.m4文件。

$ ls

autoscan.log configure.ac include main.c source

$ aclocal

$ ls

aclocal.m4 autom4te.cache autoscan.log configure.ac include main.c source

3.2.4 autoconf命令

第三步,执行autoconf命令,将configure.ac文件中的宏展开生成configure脚本。

$ ls

aclocal.m4 autom4te.cache autoscan.log configure.ac include main.c source

$ autoconf

$ ls

aclocal.m4 autom4te.cache autoscan.log configure configure.ac include main.c source

3.2.5 autoheader命令

第四部,执行autoheader命令生成config.h.in文件。

$ ls

aclocal.m4 autom4te.cache autoscan.log configure configure.ac include main.c source

$ autoheader

$ ls

aclocal.m4 autom4te.cache autoscan.log config.h.in configure configure.ac include main.c source

3.2.6 创建Makefile.am文件

第五步,创建Makefile.am文件,Automake工具会根据configure.in中的参量把Makefile.am转换成Makefile.in文件,最终通过Makefile.in生成Makefile文件。

首先在根目录下创建Makefile.am文件:

$ vim Makefile.am

$ cat Makefile.am

AUTOMAKE_OPTIONS = foreign

SUBDIRS = source

bin_PROGRAMS = hello

hello_SOURCES = main.c

hello_LDADD = source/libsrc.a

hello_CPPFLAGS = -I./include/

LIBS = -l m

注意上面的hello_LDADD指定了链接文件,hello_CPPFLAGS通过编译选项指定了编译依赖的头文件路径,LIBS指定了链接依赖的系统库。

接着在source目录下创建Makefile.am文件:

$ vim source/Makefile.am

$ cat source/Makefile.am

noinst_LIBRARIES=libsrc.a

libsrc_a_SOURCES = get.c val.c sum.c

libsrc_a_CPPFLAGS = -I../include

include_HEADERS = ../include/get.h ../include/val.h ../include/sum.h

注意上面的libsrc_a_CPPFLAGS通过编译选型指定了编译依赖的头文件路径,include_HEADERS也可以不指定,但是后续make dist打包发布时,就不会将include文件夹打包进去了。当然,也可以在上一层目录的Makefile.am文件中添加该语句:

include_HEADERS = ./include/get.h ./include/val.h ./include/sum.h

3.2.7 automake命令

第六步,执行automake --add-missing命令,生成Makefile.in文件。

$ touch NEWS README AUTHORS ChangeLog

$ automake --add-missing

configure.ac:6: warning: AM_INIT_AUTOMAKE: two- and three-arguments forms are deprecated. For more info, see:

configure.ac:6: http://www.gnu.org/software/automake/manual/automake.html#Modernize-AM_005fINIT_005fAUTOMAKE-invocation

source/Makefile.am:2: warning: compiling 'get.c' with per-target flags requires 'AM_PROG_CC_C_O' in 'configure.ac'

$ ls

aclocal.m4 autom4te.cache ChangeLog configure depcomp install-sh Makefile.am missing README

AUTHORS autoscan.log config.h.in configure.ac include main.c Makefile.in NEWS source

3.2.8 软件三部曲

接下来,就是大家非常熟悉的三部曲了:configure、make、make install。

执行./configure脚本,生成Makefile:

$ ./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... /usr/bin/mkdir -p

checking for gawk... gawk

checking whether make sets $(MAKE)... yes

checking whether make supports nested variables... yes

checking for ranlib... ranlib

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 for style of include used by make... GNU

checking dependency style of gcc... gcc3

checking how to run the C preprocessor... gcc -E

checking for grep that handles long lines and -e... /usr/bin/grep

checking for egrep... /usr/bin/grep -E

checking for ANSI C header files... yes

checking for sys/types.h... yes

checking for sys/stat.h... yes

checking for stdlib.h... yes

checking for string.h... yes

checking for memory.h... yes

checking for strings.h... yes

checking for inttypes.h... yes

checking for stdint.h... yes

checking for unistd.h... yes

checking for stdlib.h... (cached) yes

checking for unistd.h... (cached) yes

checking that generated files are newer than configure... done

configure: creating ./config.status

config.status: creating Makefile

config.status: creating source/Makefile

config.status: creating config.h

config.status: executing depfiles commands

执行make命令,生成hello可执行文件:

$ make

make all-recursive

make[1]: Entering directory `/work/study/Module/autotools/test_c3'

Making all in source

make[2]: Entering directory `/work/study/Module/autotools/test_c3/source'

gcc -DHAVE_CONFIG_H -I. -I.. -I../include -g -O2 -MT libsrc_a-get.o -MD -MP -MF .deps/libsrc_a-get.Tpo -c -o libsrc_a-get.o `test -f 'get.c' || echo './'`get.c

mv -f .deps/libsrc_a-get.Tpo .deps/libsrc_a-get.Po

gcc -DHAVE_CONFIG_H -I. -I.. -I../include -g -O2 -MT libsrc_a-val.o -MD -MP -MF .deps/libsrc_a-val.Tpo -c -o libsrc_a-val.o `test -f 'val.c' || echo './'`val.c

mv -f .deps/libsrc_a-val.Tpo .deps/libsrc_a-val.Po

gcc -DHAVE_CONFIG_H -I. -I.. -I../include -g -O2 -MT libsrc_a-sum.o -MD -MP -MF .deps/libsrc_a-sum.Tpo -c -o libsrc_a-sum.o `test -f 'sum.c' || echo './'`sum.c

mv -f .deps/libsrc_a-sum.Tpo .deps/libsrc_a-sum.Po

rm -f libsrc.a

ar cru libsrc.a libsrc_a-get.o libsrc_a-val.o libsrc_a-sum.o

ranlib libsrc.a

make[2]: Leaving directory `/work/study/Module/autotools/test_c3/source'

make[2]: Entering directory `/work/study/Module/autotools/test_c3'

gcc -DHAVE_CONFIG_H -I. -I./include/ -g -O2 -MT hello-main.o -MD -MP -MF .deps/hello-main.Tpo -c -o hello-main.o `test -f 'main.c' || echo './'`main.c

mv -f .deps/hello-main.Tpo .deps/hello-main.Po

gcc -g -O2 -o hello hello-main.o source/libsrc.a -l m

make[2]: Leaving directory `/work/study/Module/autotools/test_c3'

make[1]: Leaving directory `/work/study/Module/autotools/test_c3'

运行hello可执行程序,输出:

$ ./hello

This is val method, X:10

This is sum method!

This is main

Z:30

This is get method

Z:400

Z:3

当然,你也可以通过make install/uninstall进行安装和卸载,还可以使用make dist对软件进行打包发布。

四、常见错误及解决办法

4.1 automake报错

当执行automake --add-missing报如下错误:

error: required file './ltmain.sh' not found

请使用libtoolize配置一下即可,运行如下命令:

libtoolize --automake --copy --debug --force

查看libtoolize版本方法为:

$ libtoolize --version

libtoolize (GNU libtool) 2.4.2

Written by Gary V. Vaughan , 2003

Copyright (C) 2011 Free Software Foundation, Inc.

This is free software; see the source for copying conditions. There is NO

warranty; not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.

相关手记

质造 经典黑白 上下杯的体验
阿根廷夺冠引爆舆论 ,世界杯成平台流量密码?
户外的直播设备都要用到哪些?户外直播设备挑选指南