0 Star 4 Fork 1

极简美 / autotools_tutorial

加入 Gitee
与超过 1200万 开发者一起发现、参与优秀开源项目,私有仓库也完全免费 :)
免费加入
该仓库未声明开源许可证文件(LICENSE),使用请关注具体项目描述及其代码上游依赖。
克隆/下载
贡献代码
同步代码
取消
提示: 由于 Git 不支持空文件夾,创建文件夹后会生成空的 .keep 文件
Loading...
README

autotools

一、简介

1.1 介绍

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

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

  1. autoscan
  2. aclocal
  3. autoconf
  4. autoheader
  5. automake

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

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

sudo yum install automake

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

1.2 不同视角的程序构建

1.2.1 用户视角

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

image

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

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

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

1.2.2 开发者视角

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

  • autoreconf命令

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

image

  • 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就需要对这些宏掌握熟练,并且合理调用。

  • autoscanconfigure.scan

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

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

  • autoheaderconfigure.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包含了大量的宏定义,其中包括软件包的名字等信息,程序可以直接使用这些宏。更重要的是,程序可以根据其中的对目标平台的可移植相关的宏,通过条件编译,动态的调整编译行为。

  • automakeMakefile.am

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

  • aclocal

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

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

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

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

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

image

二、流程与规则

2.1 Autotools运行流程

  1. 执行autoscan命令,扫描工作目录并生成configure.scan文件;
  2. 修改configure.scanconfigure.ac文件,并修改配置内容;
  3. 执行aclocal命令,扫描configure.ac文件并生成aclocal.m4文件;
  4. 执行autoconf命令,将configure.ac文件中的宏展开,生成configure脚本;
  5. 执行autoheader命令,生成config.h.in文件;
  6. 创建Makefile.am文件,修改配置内容;
  7. 执行automake --add-missing命令,生成Makefile.in文件;
  8. 执行./configure命令,生成Makefile文件;
  9. 执行make命令,生成需要的库或可执行程序;
  10. 执行make install/uninstall进行安装和卸载;
  11. 执行make dist对软件进行打包工作。

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

image

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所要产生的文件,如果是makefileconfigure会把它检查出来的结果带入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 源代码讲解

  1. 主程序main.c
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>

#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;
}
  1. sum.c和sum.h
/* sum.h */
extern int sum(int x, int y);

/* sum.c */
#include <stdio.h>
#include <stdlib.h>

#include "val.h"

int sum(int x, int y)
{
	val(x);
	printf("This is sum method!\n");
	return (x + y);
}
  1. val.c和val.h
/* val.h */
extern int val(int x);

/* val.c */
#include <stdio.h>

int val(int x)
{
	printf("This is val method, X:%d\n", x);
	return x;
}
  1. get.c和get.h
/* get.h */
extern int get(int x, int y);

/* get.c */
#include <stdio.h>

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 软件三部曲

接下来,就是大家非常熟悉的三部曲了:configuremakemake 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文件即是打包发布的文件。使用发布文件的方法如下:

  1. 下载hello-1.0.tar.gz压缩包;
  2. 使用tar -zxvf hello-1.0.tar.gz命令解压;
  3. 使用./configure命令生成Makefile文件;
  4. 使用make命令编译源代码文件生成可执行程序;
  5. 使用make installmake uninstall来安装或卸载软件。

3.2 C源码在不同目录

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

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

3.2.1 源代码讲解

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

  1. 我们首先创建includesource目录,并把相应的文件放进去:
$ ls
include  main.c  source
$ ls include/
get.h  sum.h  val.h
$ ls source/
get.c  sum.c  val.c
  1. 修改main.c文件,添加调用mathabs函数:
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <math.h>

#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 软件三部曲

接下来,就是大家非常熟悉的三部曲了:configuremakemake 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 <gary@gnu.org>, 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.

空文件

简介

介绍Autotools的使用方法 展开 收起
C 等 3 种语言
取消

发行版

暂无发行版

贡献者

全部

近期动态

加载更多
不能加载更多了
C
1
https://gitee.com/simpost/autotools_tutorial.git
git@gitee.com:simpost/autotools_tutorial.git
simpost
autotools_tutorial
autotools_tutorial
master

搜索帮助