持续创作,加速成长!这是我参与「掘金日新计划 · 10 月更文挑战」的第5天, 点击查看活动详情

linux环境下,当项目工程很大的时候,编译的过程很复杂,所以需要使用make工具,自动进行编译安装,但是手写makefile文件比较复杂,所幸在GNU的计划中,设计出了一种叫做Autoconf/Automake的工具,用来自动生成makefile文件,为编译和安装程序提供了一个方便快捷的入口。

无论是在Linux还是在Unix环境中,make都是一个非常重要的编译命令。不管是自己进行项目开发还是安装应用软件,我们都经常要用到make或 make install。利用make工具,我们可以将大型的开发项目分解成为多个更易于管理的模块,对于一个包括几百个源文件的应用程序,使用make和 makefile工具就可以轻而易举的理顺各个源文件之间纷繁复杂的相互关系。

但是如果通过查阅make的帮助文档来手工编写Makefile,对任何程序员都是一场挑战。

下面将介绍如何利用 GNU Autoconf 及 Automake 这两套工具来协助我们自动产生 Makefile文件,并且让开发出来的软件可以像大多数源码包那样,只需"./configure", "make","make install" 就可以把程序安装到系统中。

目前automake支持三种目录层次:flat、shallow和deep。

  • flat指的是所有文件都位于同一个目录中。
  • 就是所有源文件、头文件以及其他库文件都位于当前目录中,且没有子目录。Termutils就是这一类。

  • shallow指的是主要的源代码都储存在顶层目录,其他各个部分则储存在子目录中。
  • 就是主要源文件在当前目录中,而其它一些实现各部分功能的源文件位于各自不同的目录。automake本身就是这一类。

  • deep指的是所有源代码都被储存在子目录中;顶层目录主要包含配置信息。
  • 就是所有源文件及自己写的头文件位于当前目录的一个子目录中,而当前目录里没有任何源文件。

    二、安装Automake工具

  • 先检查当前系统里是否安装了工具。
  • 3. 2 执行autoscan命令生成configure.scan文件

    生成configure.scan文件之后,将文件修改成configure.ac文件,如果没有这个.ac文件,执行aclocal命令的时候会报错。

    3.3 修改configure.ac文件参数

    AC_PROG_RANLIB如果是多线程的程序的话要加入这句话,要不运行automake命令时会出错

    每个configure.ac文件都是以AC_INIT开头,以AC_OUTPUT结束。

    AC_OUTPUT(Makefile)

    (1)AC_PREREQ宏声明本文件要求的autoconf版本,本例使用的版本为2.63。

    (2)AC_INIT宏用来定义软件的名称和版本等信息,”FULL-PACKAGE-NAME”为软件包名称,”VERSION”为软件版本号,”BUG-REPORT-ADDRESS”为BUG报告地址(一般为软件作者邮件地址)。

    (3)AC_CONFIG_SRCDIR宏用来侦测所指定的源码文件是否存在,来确定源码目录的有效性。此处为当前目录下的app.c。

    (4)AC_CONFIG_HEADER宏用于生成config.h文件,以便autoheader使用。

    (5)AC_PROG_CC用来指定编译器,如果不指定,选用默认gcc。 比如: AC_PROG_CC(gcc)

    (6)AC_OUTPUT用来设定 configure 所要产生的文件,如果是makefile,configure会把它检查出来的结果带入makefile.in文件产生合适的makefile。使用Automake时,还需要一些其他的参数,这些额外的宏用aclocal工具产生。

    3.4 执行aclocal命令生成aclocal.m4文件

    3.7 手工编辑Makefile.am文件

    Automake工具会根据config.in中的参量把Makefile.am转换成Makefile.in文件。在使用Automake之前,要先手动建立Makefile.am文件。

    Makefile.am是一种比Makefile更高层次的规则。只需指定要生成什么目标,它由什么源文件生成,要安装到什么目录等构成。

    3.8 使用automake命令生成Makefile.in文件

    添加选项--add-missing 可以让automake工具自动添加必要的脚本文件

    注意: 不能在共享目录下执行,因为共享目录下是windows文件系统(FA32/NTFS),不支持link操作。

    不然会报以下错误:

    3.9 运行configure配置生成最终的Makefile文件

    configure脚本为了让一个程序能够在各种不同类型的机器上运行而设计的。在使用make编译源代码之前,configure会根据自己所依赖的库而在目标机器上进行匹配。

    约定俗成的,所有的configure脚本都把脚本文件名起为configure,一般来讲都是shell脚本,根据所在的系统环境生成makefile文件。

    configure脚本运行时扫描当前环境,生成一个名为config.status的子脚本。子脚本将Makefile.in文件转换为适应于当前系统环境的Makefile文件。

    [wbyq@wbyq tmp] . / c o n f i g u r e c h e c k i n g f o r a B S D c o m p a t i b l e i n s t a l l . . . / u s r / b i n / i n s t a l l c c h e c k i n g w h e t h e r b u i l d e n v i r o n m e n t i s s a n e . . . y e s c h e c k i n g f o r a t h r e a d s a f e m k d i r p . . . / b i n / m k d i r p c h e c k i n g f o r g a w k . . . g a w k c h e c k i n g w h e t h e r m a k e s e t s ./configurechecking for a BSD-compatible install... /usr/bin/install -cchecking whether build environment is sane... yeschecking for a thread-safe mkdir -p... /bin/mkdir -pchecking for gawk... gawkchecking whether make sets

    3.10 使用Makefile编译,运行程序

    [wbyq@wbyq tmp] m a k e / / 编译程序 [ w b y q @ w b y q t m p ] make //编译程序[wbyq@wbyq tmp] ./app 123 456 789 //运行程序argv[0]=./appargv[1]=123argv[2]=456argv[3]=789

    3.11 Make支持的其他命令

    [wbyq@wbyq app-1.1.2] m a k e c l e a n / / 清除目标文件 [ w b y q @ w b y q a p p 1.1.2 ] make clean //清除目标文件[wbyq@wbyq app-1.1.2]

    四、configure文件详解

    configure' configures app 1.2.3 to adapt to many kinds of systems.Usage: ./configure [OPTION]... [VAR=VALUE]...To assign environment variables (e.g., CC, CFLAGS...), specify them asVAR=VALUE. See below for descriptions of some of the useful variables.Defaults for the options are specified in brackets.Configuration:-h, --help 显示此帮助并退出--help=short 显示特定于此包的选项--help=recursive 显示所有包含的简短帮助-V, --version 显示版本信息并退出-q, --quiet, --silent 不要打印“检查...”消息--cache-file=FILE 在FILE中缓存测试结果[已禁用]-C, --config-cache alias for --cache-file=config.cache'-n, --no-create do not create output files--srcdir=DIR find the sources in DIR [configure dir or ..']Installation directories:--prefix=PREFIX 在PREFIX中安装与体系结构无关的文件[/usr/local]--exec-prefix=EPREFIX 在EPREFIX中安装与体系结构相关的文件[PREFIX]By default, make install' will install all the files in /usr/local/bin', /usr/local/lib' etc. You can specifyan installation prefix other than /usr/local' using --prefix',for instance --prefix=$HOME'.For better control, use the options below.Fine tuning of the installation directories:--bindir=DIR 用户可执行文件 [EPREFIX/bin]--sbindir=DIR 系统管理可执行文件 [EPREFIX/sbin]--libexecdir=DIR 程序可执行文件 [EPREFIX/libexec]--sysconfdir=DIR read-only single-machine data [PREFIX/etc]--sharedstatedir=DIR modifiable architecture-independent data [PREFIX/com]--localstatedir=DIR modifiable single-machine data [PREFIX/var]--libdir=DIR 目标代码库 [EPREFIX/lib]--includedir=DIR C header files [PREFIX/include]--oldincludedir=DIR C header files for non-gcc [/usr/include]--datarootdir=DIR read-only arch.-independent data root [PREFIX/share]--datadir=DIR read-only architecture-independent data [DATAROOTDIR]--infodir=DIR info documentation [DATAROOTDIR/info]--localedir=DIR locale-dependent data [DATAROOTDIR/locale]--mandir=DIR man documentation [DATAROOTDIR/man]--docdir=DIR documentation root [DATAROOTDIR/doc/app]--htmldir=DIR html documentation [DOCDIR]--dvidir=DIR dvi documentation [DOCDIR]--pdfdir=DIR pdf documentation [DOCDIR]--psdir=DIR ps documentation [DOCDIR]Program names:--program-prefix=PREFIX prepend PREFIX to installed program names--program-suffix=SUFFIX append SUFFIX to installed program names--program-transform-name=PROGRAM run sed PROGRAM on installed program namesOptional Features:--disable-option-checking ignore unrecognized --enable/--with options--disable-FEATURE do not include FEATURE (same as --enable-FEATURE=no)--enable-FEATURE[=ARG] include FEATURE [ARG=yes]--disable-dependency-tracking speeds up one-time build--enable-dependency-tracking do not reject slow dependency extractorsSome influential environment variables:CC C compiler commandCFLAGS C compiler flagsLDFLAGS linker flags, e.g. -L<lib dir> if you have libraries in anonstandard directory <lib dir>LIBS libraries to pass to the linker, e.g. -l<library>CPPFLAGS C/C++/Objective C preprocessor flags, e.g. -I<include dir> ifyou have headers in a nonstandard directory <include dir>CPP C preprocessorUse these variables to override the choices made by configure' or to helpit to find libraries and programs with nonstandard names/locations.Report bugs to 1126626497@qq.com .

    五、多个文件生成Makefile示例(同级目录)

    ​ 在目录下有3个.c、2个头文件

    ​ configure.ac文件内容:

    ​ Makefile.am文件内容:

    六、Makefile.am格式详解

    6.1 Makefile.am中可用的全局变量

    变量 含义 示例
    INCLUDES 链接所需要的头文件
    LDADD 链接所需要的库文件
    LDFLAGS 链接所需要的库文件选项标志
    EXTRA_DIST 配置打包时需要打包的其他文件
    SUBDIRS 设置处理本目录之前需要递归处理的子目录
    SUBDIRS=src/lib src/ModuleA/apple/shell src/ModuleA/apple/coreCURRENTPATH= ( s h e l l / b i n / p w d ) I N C L U D E S = I (shell /bin/pwd)INCLUDES=-I

    6.2 Makefile.am中可用的路径变量

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

    路径变量 含义
    $(top_srcdir) 工程最顶层目录,用于引用源程序
    $(top_builddir) 定义了生成目标文件最上层目录,用于引用.o 等一些编译出来的目标文件
    $(prefix) 定义了软件的安装的路径
  • automake标准安装路径
  • 默认安装路径为:$(prefix) = /usr/local,可以通过./configure --prefix=<new_path>的方法来覆盖。

    其它的预定义目录还包括:bindir = ( p r e f i x ) / b i n , l i b d i r = (prefix)/bin, libdir =

  • 定义一个新的安装路径
  • 比如test, 可定义testdir = ( p r e f i x ) / t e s t , 然后 t e s t D A T A = t e s t 1 t e s t 2 ,则 t e s t 1 t e s t 2 会作为数据文件安装到 (prefix)/test, 然后test_DATA =test1 test2,则test1,test2会作为数据文件安装到

    devicedir = ${prefix}/devdevice_DATA = packagepackage文件会作为数据文件安装到dev目录之下,这相当于定义了一种安装类型:devicedir,所以想怎么安装就怎么安装,后面的XXXXXdir,dir是固定不变的

    6.3 Makefile.am一般格式Makefile.am一般格式

    PROGRAMS。表示可执行文件

    LIBRARIES。表示静态库文件

    LTLIBRARIES。表示动态库文件,前面的LT表示libtool。

    HEADERS。头文件。

    SCRIPTS。脚本文件,这个可以被用于执行。如:example_SCRIPTS,如果用这样的话,需要我们自己定义安装目录下的example目录

    DATA。数据文件,不能执行。

    文件类型 书写格式 示例
    软件规范 AUTOMAKE_OPTIONS=foreign 有三个候选项:foreign(国外),gnu(GNU),gnits如果使用foreign等级,它只检测必须的文
    可执行文件 bin_PROGRAMS=foofoo_SOURCES=xxx.cfoo_LDADD=foo_LDFLAGS=foo_DEPENDENCIES= bin_PROGRAMS=foo(设置可执行文件的名称)如果可执行文件的名称为foo,后面的代码前缀,都需要填foo
    静态库 lib_LIBRARIES=libfoo.afoo_a_SOURCES=foo_a_LDADD=foo_a_LIBADD=foo_a_LDFLAGS= 如果程序里使用了静态库编译,需要在configure.ac文件里增加以下宏定义代码AC_PROG_RANLIB
    动态库 lib_LTLIBRARIES=libfoo.lafoo_la_SOURCES=foo_la_LDADD=foo_la_LIBADD=foo_la_LDFLAGS= 如果程序里使用了动态库编译,需要在configure.ac文件里增加以下宏定义代码AC_PROG_LIBTOOL表示利用libtool 来自动生成动态库编译共享库前,需要运行以下命令:libtoolize -f -c
    头文件 include_HEADERS=xx.h xx.h xx.h 软件发布时需要的头文件make install之后,会将头文件放到安装目录下的include目录里。
    数据文件 data_DATA=data1 xxx2 xxx3

    对于可执行文件和静态库类型,如果只想编译,不想安装到系统中,可以用noinst_PROGRAMS代替bin_PROGRAMS,noinst_LIBRARIES代替lib_LIBRARIES。

    如果有帮助文档,不需要编译,但是需要随着软件发布一起发布,可以按下面格式进行定义:

    七、auotomake多级目录生成Makefile(不发布静态库)

    7.1 创建待编译的源码(模拟真实项目环境)

    在第一章里简单介绍了使用automake自动产生makefile的几个关键步骤,所有文件都在同一个目录下。但在比较大的项目中,很少将所有文件放在一个目录下的。下面将针对这种情况做个简单介绍。

    多级目录结构的软件,一般是单个程序、库文件或模块放在各自的目录中。automake要求每个目录都有自己的Makefile.am文件来编译各自目录 下的代码。在顶级的目录中,有一个Makefile.am文件,该文件通过SUBDIRS指明了这个目录下有多少个直接下级目录的代码需要编译。下级目录的Makefile.am也指明自己需要编译的下级目录。通过这样的层层递归i,从而完成多级目录结构的编译。

    下面模拟了一个项目工程:

    顶层目录是project,在project目录下分别是main\print\sum目录。 main目录里的main.c是包含main函数的主程序,分别调用了sum和print目录下.c文件里的函数。

    7.2 project顶层目录下的操作过程

  • 执行autoscan命令生成configure.scan文件
  • 在project目录下运行autoscan命令生成configure.scan文件。

  • 将configure.scan改名成configure.in (早期in现在常用.ac)
  • [wbyq@wbyq project]$ cat configure.in# - - Autoconf - -# Process this file with autoconf to produce a configure script.AC_PREREQ([2.63])AC_INIT([app], [1.2.3], [ 112626497@qq.com ])AC_CONFIG_SRCDIR([main/main.c])AC_CONFIG_HEADERS([config.h])AM_INIT_AUTOMAKE(app,1.2.3)AC_PROG_RANLIB #使用了静态库编译,需要此宏定义# 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(Makefilemain/Makefilesum/Makefileprint/Makefile)
  • 分别执行aclocal、autoconf、autoheader命令
  • 创建Makefile.am文件
  • EXTRA_DIST=doc/help.txt

    doc/help.txt不需要编译,但要发布该文件。如果有多个文件,则用空格分开。

    7.3 main目录下创建Makefile.am文件

    在main目录下建立Makefile.am文件。

    AUTOMAKE_OPTIONS=foreignbin_PROGRAMS=app #本目录的文件编译成可执行文件appapp_SOURCES=main.capp_LDADD= ( t o p s r c d i r ) / s u m / l i b s u m . a (top_srcdir)/sum/libsum.a

    app_LDADD 指定需要的库文件

    INCLUDES 指定需要的头文件

    7.4 print目录下创建Makefile.am文件

    [wbyq@wbyq project] cat print/Makefile.amAUTOMAKE_OPTIONS=foreignnoinst_LIBRARIES=libprint.alibprint_a_SOURCES=print.h print.cINCLUDES=-I (top_srcdir)/sum

    7.5 sum目录下创建Makefile.am文件

    [wbyq@wbyq project]$ cat sum/Makefile.amAUTOMAKE_OPTIONS=foreignnoinst_LIBRARIES=libsum.alibsum_a_SOURCES=sum.h sum.c

    7.6 编译

    [wbyq@wbyq project] a u t o m a k e a d d m i s s i n g [ w b y q @ w b y q p r o j e c t ] automake --add-missing[wbyq@wbyq project]

    八、auotomake多级目录生成Makefile(发布静态库)

  • 目录结构如下
  • 在main.里调用了led.c和key.c里的函数。

    (1)​ main.c代码

    [wbyq@wbyq project]$ cat user/main.c#include <stdio.h>#include "key.h"#include "led.h"int main(char argc,char **argv){led_init();key_init();return 0;}

    (2)​ led.c和led.h代码

    [wbyq@wbyq project] cat led/led.h#ifndef LED_H#define LED_H#include <stdio.h>void led_init(void);#endif[wbyq@wbyq project] cat led/led.c#include "led.h"void led_init(void){printf("led_init\n");}

    (3)​ key.c和key.h代码

    [wbyq@wbyq project] cat key/key.h#ifndef KEY_H#define KEY_H#include <stdio.h>void key_init(void);#endif[wbyq@wbyq project] cat key/key.c#include "key.h"#include "led.h"void key_init(void){led_init();printf("key_init\n");}

    调用关系图

  • 顶层Makefile.am文件代码(自己创建)
  • [wbyq@wbyq project]$ cat Makefile.amAUTOMAKE_OPTIONS=foreign #软件规范SUBDIRS=led key user #执行本目录前,需要递归执行make的目录
  • user/Makefile.am文件代码(自己创建)
  • [wbyq@wbyq project] cat user/Makefile.amAUTOMAKE_OPTIONS=foreign #软件规范bin_PROGRAMS=app #可执行文件名称app_SOURCES=main.c #可执行需要的源文件app_LDADD= (top_srcdir)/led/libled.a (top_srcdir)/key/libkey.a #可执行文件需要的库文件INCLUDES=-I (top_srcdir)/led -I (top_srcdir)/key #编译需要的头文件EXTRA_DIST= (top_srcdir)/led/led.h $(top_srcdir)/key/key.h #打包时需要额外添加的文件 make dist打包命令
  • key/Makefile.am文件代码(自己创建)
  • [wbyq@wbyq project]$ cat key/Makefile.amAUTOMAKE_OPTIONS=foreign #软件规范lib_LIBRARIES=libkey.a #生成的静态库文件libkey_a_SOURCES=key.c key.h #生成静态库需要的源文件。 格式:libkey_a_SOURCES --将原来的.换成_
  • led/Makefile.am文件代码(自己创建)
  • [wbyq@wbyq project]$ cat led/Makefile.amAUTOMAKE_OPTIONS=foreign #软件规范lib_LIBRARIES=libled.a #生成的静态库文件(lib开头表示执行make installs时会一起发布,加noinst就不会一起发布)libled_a_SOURCES=led.c led.h #生成静态库需要的源文件。 格式:libkey_a_SOURCES --将原来的.换成_
  • 顶层目录下的configure.ac 文件代码
  • 1. 执行autoscan 命令生成configure.scan 文件2. 修改configure.scan 文件后缀为.ac或者.in3. 修改configure.ac 文件参数4. configure.ac文件代码如下:[wbyq@wbyq project]$ cat configure.ac# - - Autoconf - -# Process this file with autoconf to produce a configure script.AC_PREREQ([2.63])AC_INIT([app], [1.2.3], [ 112662497@qq.com ])AC_CONFIG_SRCDIR([user/main.c])AC_CONFIG_HEADERS([config.h])AM_INIT_AUTOMAKE(app,1.2.3)AC_PROG_RANLIB #表示使用静态库# Checks for programs.AC_PROG_CC# Checks for library functions.AC_OUTPUT(Makefileuser/Makefileled/Makefilekey/Makefile)

    执行命令: aclocal\autoconf\autoheader

    automake --add-missing

    ./configure --prefix=$PWD/_install

    make && make install

    在安装目录下的文件结果

    九、auotomake多级目录生成Makefile(发布动态库+静态库)

  • 目录结构如下
  • 在main.里调用了led.c和key.c里的函数。

    在main.里调用了led.c和key.c里的函数。

    (1)​ main.c代码

    [wbyq@wbyq project]$ cat user/main.c#include <stdio.h>#include "key.h"#include "led.h"int main(char argc,char **argv){led_init();key_init();return 0;}

    (2)​ led.c和led.h代码

    [wbyq@wbyq project] cat led/led.h#ifndef LED_H#define LED_H#include <stdio.h>void led_init(void);#endif[wbyq@wbyq project] cat led/led.c#include "led.h"void led_init(void){printf("led_init\n");}

    (3)​ key.c和key.h代码

    [wbyq@wbyq project] cat key/key.h#ifndef KEY_H#define KEY_H#include <stdio.h>void key_init(void);#endif[wbyq@wbyq project] cat key/key.c#include "key.h"#include "led.h"void key_init(void){led_init();printf("key_init\n");}

    调用关系图

  • 顶层Makefile.am文件代码(自己创建)
  • [wbyq@wbyq project]$ cat Makefile.amAUTOMAKE_OPTIONS=foreign #软件规范SUBDIRS=led key user #执行本目录前,需要递归执行make的目录
  • user/Makefile.am文件代码(自己创建)
  • [wbyq@wbyq project] cat user/Makefile.amAUTOMAKE_OPTIONS=foreign #软件规范bin_PROGRAMS=app #可执行文件名称app_SOURCES=main.c #可执行需要的源文件app_LDADD= (top_srcdir)/led/libled.la (top_srcdir)/key/libkey.la #可执行文件需要的动态库文件INCLUDES=-I (top_srcdir)/led -I (top_srcdir)/key #编译需要的头文件EXTRA_DIST= (top_srcdir)/led/led.h $(top_srcdir)/key/key.h #打包时需要额外添加的文件 make dist打包命令
  • key/Makefile.am文件代码(自己创建)
  • [wbyq@wbyq project]$ cat key/Makefile.amAUTOMAKE_OPTIONS=foreign #软件规范lib_LTLIBRARIES=libkey.la #生成的动态库文件libkey_la_SOURCES =key.c key.h #生成静态库需要的源文件。 格式:libkey_la_SOURCES --将原来的.换成_
  • led/Makefile.am文件代码(自己创建)
  • [wbyq@wbyq project]$ cat led/Makefile.amAUTOMAKE_OPTIONS=foreign #软件规范lib_ LTLIBRARIES =libled.la #生成的动态库文件(lib开头表示执行make installs时会一起发布,加noinst就不会一起发布)libled_la_SOURCES=led.c led.h #生成静态库需要的源文件。 格式:libkey_la_SOURCES --将原来的.换成_
  • 顶层目录下的configure.ac 文件代码
  • 1. 执行autoscan 命令生成configure.scan 文件2. 修改configure.scan 文件后缀为.ac或者.in3. 修改configure.ac 文件参数4. configure.ac文件代码如下:[wbyq@wbyq project]$ cat configure.ac# - - Autoconf - -# Process this file with autoconf to produce a configure script.AC_PREREQ([2.63])AC_INIT([app], [1.2.3], [ 112662497@qq.com ])AC_CONFIG_SRCDIR([user/main.c])AC_CONFIG_HEADERS([config.h])AM_INIT_AUTOMAKE(app,1.2.3)AC_PROG_LIBTOOL#使用动态库# Checks for programs.AC_PROG_CC# Checks for library functions.AC_OUTPUT(Makefileuser/Makefileled/Makefilekey/Makefile)

    执行命令: aclocal\autoconf\autoheader

    执行命令: libtoolize -f -c #共享库必须要执行

    automake --add-missing

    ./configure --prefix=$PWD/_install

    make && make install

    在安装目录下的文件结果

    十、自定义安装目录示例(make install)

    wbyqdir= ( p r e f i x ) / w b y q 6 66 w b y q D A T A = (prefix)/wbyq_666wbyq_DATA=

    wbyq:表示是新的路径类型。

    wbyq_666:表示在安装路径下创建的目录名称。

    666.c、888.c :是执行make install 拷贝到wbyq_666目录下的文件。

    十一、多级目录与函数的嵌套调用生成Makefile

    [wbyq@wbyq project] cat main/main.c#include <stdio.h>#include "print.h"int main(){int a=123;int b=456;print(a,b);}[wbyq@wbyq project] cat sum/sum.h#ifndef _SUM_H#define _SUM_Hint sum(int,int);#endif[wbyq@wbyq project] cat sum/sum.c#include "sum.h"int sum(int a,int b){int c;c=sum(a,b);return c;}[wbyq@wbyq project] cat print/print.h#ifndef _PRINT_H#define _PRINT_H#include "sum.h"#include <stdio.h>void print(int,int);#endif[wbyq@wbyq project]$ cat print/print.c#include "print.h"void print(int a,int b){int c;c=sum(a,b);printf("%d\n",c);}

    图11.1 C文件的调用关系图

    [wbyq@wbyq project] a u t o s c a n [ w b y q @ w b y q p r o j e c t ] autoscan[wbyq@wbyq project] mv configure.scan configure.ac[wbyq@wbyq project] v i m c o n f i g u r e . a c [ w b y q @ w b y q p r o j e c t ] vim configure.ac[wbyq@wbyq project] cat configure.acAC_PREREQ([2.63])AC_INIT([app], [1.2.3], [ 112662497@qq.com ])AC_CONFIG_SRCDIR([main/main.c])AC_CONFIG_HEADERS([config.h])AM_INIT_AUTOMAKE(app,1.2.3)AC_PROG_RANLIB #使用了静态库编译,需要此宏定义AC_PROG_CCAC_OUTPUT(Makefile main/Makefile print/Makefile sum/Makefile)[wbyq@wbyq project] a c l o c a l [ w b y q @ w b y q p r o j e c t ] aclocal[wbyq@wbyq project] autoconf[wbyq@wbyq project] a u t o h e a d e r [ w b y q @ w b y q p r o j e c t ] autoheader[wbyq@wbyq project] vim Makefile.am[wbyq@wbyq project] c a t M a k e f i l e . a m A U T O M A K E O P T I O N S = f o r e i g n S U B D I R S = s u m p r i n t m a i n [ w b y q @ w b y q p r o j e c t ] cat Makefile.amAUTOMAKE_OPTIONS=foreignSUBDIRS= sum print main[wbyq@wbyq project]