运用 autoconf 和 automake 自动生成 Makefile 实例讲解

本文详细介绍如何使用Autoconf和Automake自动生成Makefile,使软件可在多种UNIX类系统上轻松编译安装。涵盖配置文件编写、命令使用及示例程序。

对于一个 UNIX/Linux C 程序员来说,一个比较麻烦的工作就是写自己的 Makefile
可能你有如下经验:写一个简单的 C 程序,自己多写几行 gcc 命令就把程序变成可执行的了;写一个稍微复杂点的程序,源文件个数可能在 30 个左右,还是写一行行的 gcc 命令就麻烦了,你可能想到写个 makefile ,你可能也在这样做着;但你某一天会发现你写的这个 Makefile 可能不是一个所有 UNIX/Linux 类操作系统下通用的 Makefile ,比如某人下载了你的程序去他自己电脑上可能 make 不了。

这样,你就有必要了解并学会运用 autoconf automake 了。
autoconf
是一个用于生成可以自动地配置软件源代码包以适应多种 UNIX 类系统的 shell 脚本的工具。由 autoconf 生成的配置脚本在运行的时候不需要用户的手工干预;通常它们甚至不需要手工给出参数以确 定系统的类型。相反,它们对软件包可能需要的各种特征进行独立的测试。在每个测试之前,它们打印一个单行的消息以说明它们正在进行的检测,以使得用户不会 因为等待脚本执行完毕而焦躁。因此,它们在混合系统或者从各种常见 UNIX 变种定制而成的系统中工作的很好。你也省了工作,没必要维护文件以储存由各个 UNIX 变种、各个发行版本所支持的特征的列表。
automake
是一个从文件 Makefile.am 自动生成 Makefile.in 的工具。每个 Makefile.am 基本上是一系列 make 的宏定义( make 规则也会偶尔出现)生成的 Makefile.in ,服从 GNU Makefile 标准。
为了生成 Makefile.in automake 需要 perl 。但是由 automake 创建的发布完全服从 GNU 标准,并且在创建中不需要 perl

在开始使用 autoconf automake 之前,首先确认你的系统安装有 GNU 的如下软件:
1. automake
2. autoconf
3. m4
4. perl
5.
如果你需要产生共享库( shared library )则还需要 GNU Libtool

介绍方法之前大家看一下下面这个图,先记下 autoconf automake 工作的几个步骤:


步骤解释如下:
1
、由你的源文件通过 autoscan 命令生成 configure.scan 文件,然后修改 configure.scan 文件并重命名为 configure.in
2
、由 aclocal 命令生成 aclocal.m4
3
、由 autoconf 命令生成 configure
4
、编辑一个 Makefile.am 文件并由 automake 命令生成 Makefile.in 文件
5
、运行 configure 命令生成 Makefile

automake
支持三种目录层次: flat shallow deep
一个 flat 包指的是所有文件都在一个目录中的包。为这类包提供的 Makefile.am 不需要 SUBDIRS 这个宏。这类包的一个例子是 termutils 。对应咱们程序员来说:就是所有源文件及自己写的头文件都位于当前目录里面,且没有子目录。
一个 deep 包指的是所有的源代码都被储存在子目录中的包;顶层目录主要包含配置信息。 GNU cpio 是这类包的一个很好的例子, GNU tar 也是。 deep 包的顶层 Makefile.am 将包括宏 SUBDIRS ,但没有其它定义需要创建的对象的宏。对应咱们程序员来说:就是所有源文件及自己写的头文件都位于当前目录的一个子目录里面,而当前目录里没有任何源文件。
一个 shallow 包指的是主要的源代码储存在顶层目录中,而各个部分(典型的是库)则储存在子目录中的包。 automake 本身就是这类包( GNU make 也是如此,它现在已经不使用 automake )。对应咱们程序员来说:就是主要源文件在当前目录里,而其它一些实现各部分功能的源文件各自位于不同目录。

前两个层次的程序编辑方法非常简单,按照上述步骤一步步即可。而第三种层次 shallow 稍微复杂一点,但这是我们经常写程序用到的结构。下面以一个例子说明 shallow 层次结构的源文件如何自动生成 Makefile 文件。
例子源程序结构如下:
hello
是我们的工作目录, hello 目录下有 main.c 源文件和 comm tools db network interface 等五个目录。 comm 目录下有 comm.c comm.h 源文件及头文件, tools 目录下有 tools.c tools.h ,同样其它目录分别有 db.c db.h network.c network.h interface.c interface.h 等一些源文件。

按照如下步骤来自动生成 Makefile 吧:
1
、进入 hello 目录,运行 autoscan 命令,命令如下:
cd hello
autoscan
2
ls 会发现多了一个 configure.scan 文件。修改此文件,在 AC_INIT 宏之后加入 AM_INIT_AUTOMAKE(hello, 1.0) ,这里 hello 是你的软件名称, 1.0 是版本号,即你的这些源程序编译将生成一个软件 hello-1.0 版。然后把 configure.scan 文件的最后一行 AC_OUTPUT 宏填写完整变成 AC_OUTPUT(Makefile) ,表明 autoconf automake 最终将生成 Makefile 文件。最后把 configure.scan 文件改名为 configure.in 。最终 configure.in 文件内容如下:

# Process this file with autoconf to produce a configure script.
AC_INIT(target.c)
AM_INIT_AUTOMAKE(hello, 1.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)

3
、运行 aclocal 命令, ls 会发现多了一个 aclocal.m4 文件。
4
、然后运行 autoconf 命令, ls 将发现生成了一个可执行的 configure 命令。
5
、编辑一个 Makefile.am 文件,文件内容如下:
AUTOMAKE_OPTIONS=foreign
bin_PROGRAMS=hello
hello_SOURCES=main.c comm/comm.c comm/comm.h tools/tools.c tools/tools.h db/db.c db/db.h network/network.c network/network.h interface/interface.c interface/interface.h
这表明你最后将通过一个 make 命令利用上述 hello_SOURCES 源文件生成一个 hello 的程序。
6
、运行 automake --add-missing 命令。屏幕提示如下:
automake: configure.in: installing `./install-sh'
automake: configure.in: installing `./mkinstalldirs'
automake: configure.in: installing `./missing'
7
、然后你可以运行之前生成的 configure 命令来生成一个 Makefile 文件,输入 ./configure 命令即可。
8
、编辑 Makefile 文件,找到 $(LINK) 所在的那一行,本来生成的文件内容如下:
@rm -f hello
$(LINK) $(hello_LDFLAGS) $(hello_OBJECTS) $(hello_LDADD) $(LIBS)
在这两行之间增加几行变成:
@rm -f hello
@mv -f comm.o comm
@mv -f tools.o tools
@mv -f db.o db
@mv -f network.o network
@mv -f interface.o interface
$(LINK) $(hello_LDFLAGS) $(hello_OBJECTS) $(hello_LDADD) $(LIBS)
这是因为默认生成的 Makefile 将在编译后把所有目标文件置于当前目录,而在进行链接 (link) 时又会到各个子目录去找相应的目标文件。
当然,为了完整,建议各位在 clean 部分加上如下一些行:
@rm -f comm/comm.o
@rm -f tools/tools.o
@rm -f db/db.o
@rm -f network/network.o
@rm -f interface/interface.o

好了,经过上述这些步骤后,现在你可以来编译生成你自己的可执行程序了。输入一个 make all 吧,然后就可以运行 ./hello 来看你的程序运行了。

运用 autoconf automake 的最大好处是,你的程序以源程序方式发布后,其它所有人只需要依次输入
./configure
make
make install
命令就可以把你的程序安装在自己的电脑上运行了。所有符合 GNU 标准的 UNIX/Linux 都不需要再修改 Makefile 里的任何字符。

 

1,运转起来
先看最简单的情况,让它运转起来,掌握基本步骤。
假设有源文件hello.h/c放在hello目录下。
第一步:
在hello目录下运行autoscan会生成configure.scan文件,同时打印错误提示"Can't find configure.ac"(原因不明,但不要紧)。
第二步:
将configure.scan改名为configure.in。并进行编辑,修改其中的
AC_INIT(hello, 1.0, you@example.com) 即程序名,版本,你的email
AC_OUTPUT(Makefile) 即configure运行后输出的东西有哪些,一般是每个文件夹下一个Makefile
AC_CHECK_LIB([pthread],[pthread_create],,[AC_MSG_ERROR([libpthread is missing])]) 如果你需要链接一些库则用这个进行检查且加入到LIBS变量中(后面细讲)
加入一行
AM_INIT_AUTOMAKE 有了这行才能使用automake生成Makefile.in
第三步:
运行aclocal生成需要的宏(macro,autoconf和automake其实都是在为一些宏赋值)
第四步:
运行autoconf生成configure
第五步:
为每个目录写Makefile.am(这例中只有一个)
内容如下:
AUTOMAKE_OPTIONS=foreigh
bin_PROGRAMS=hello
hello_SOURCES=xxxx xxxx表示所有于生成hello有关的源文件.h/.c这里是hello.h/c
第六步:
运行autoheader
第七步:
运行automake --add-missing --copy
完成。
现在可以./configure; make; make install; make xxx等

2,标准步骤
下图从autoconf手册中来。[]括起来的的是可能出现的文件,加*的是执行文件。
生成Makefile.in和configure等的过程:
your source files --> [autoscan*] --> [configure.scan] --> configure.ac

configure.ac --.
| .------> autoconf* -----> configure
[aclocal.m4] --+---+
| `-----> [autoheader*] --> [config.h.in]
[acsite.m4] ---'

Makefile.in -------------------------------> Makefile.in

生成Makefile以编译安装过程:

.-------------> [config.cache]
configure* ------------+-------------> config.log
|
[config.h.in] -. v .-> [config.h] -.
+--> config.status* -+ +--> make*
Makefile.in ---' `-> Makefile ---'


3,几个重要的宏
从前面可以看出重点有两个:修改configure.in和编辑Makefile.am
事实上,它们都是用一些宏来获取相关信息。重要的宏有:
configure.in中
AC_INIT([xxx],[yyy],[zzz],[aaa]) 可以有四个参数,前三个必须。第一个是软件包的名字,一个字符串(可以用空格,不需用引号);第二个是版本,如0.6;地三个是报告bug的email; 地四个是make dist时创建的tar的名字。如果不填(前面的逗号也去掉)的话默认为xxx(但是会有变化,例如xxx为My hello则创建my-hello.tar.gz)

AC_OUTPUT([xxx]) 指出运行configure后输出那些文件,一般就是每个文件夹下的Makefile,如AC_OUTPUT([Makefile, src/Makefile, doc/Makefile])

AC_CHECK_LIB([xxx],[yyy],[zzz],[aaa]) 这个用来检查系统中是否安装了某个库。xxx是库名去掉前面的lib后面的扩展名;yyy是库xxx中的任一函数名;zzz是当存在时做什么操作,建议留 空([]也去掉),因为默认情况就是把该库加入到LIBS变量中,即加入-lxxx,如果改了的话就不加了;aaa是当不存在时的操作,可以用 AC_MSG_ERROR([xxx is needed]),它将在运行configure时打印“xxx is needed”并退出。

AM_INIT_AUTOMAKE(xxx, yyy) 可以不加参数(同时去掉括号),xxx指包名(这里的包名不能有空格,就算用引号也不管用),yyy指版本号

Makefile.am中
AUTOMAKE_OPTIONS=xxx xxx为gnu,foreign,和gnits。指用什么风格的工程,如果是gnu则必须要自己写AUTHOR,NEWS等文件;一般用foreign,在automake时会给你照搬一套默认的AUTHOR,NEWS等文件。

bin_PROGRAMS=xxx 指定最后生成的可执行文件的名字,即Makefile的目标,不一定要和包名相同。指定了这个之后,make install会把该目标拷贝到prefix/bin目录下。很明显类似的有 sbin_PROGRAMS,lib_LIBRARIES,sysconf_DATA,man_MANS等,这个在《GNU编码标准》中有列 表,automake做了一些扩展,但是一些简单应用只要知道这几个就行了;例如指定man_MANS=hello.man.3则会把该文件安装到 prefix/man目录下,指定sysconf_DATA=hello.conf就会把配置文件放到prefix/etc目录下。 xxx_SOURCES=yyy 这里指定所有与xxx有关的源文件。注意,不要把其他目录下的文件放进去。例如,如果xxx用到了../comm目录下的debug.c,不要加到后面, 这样会在本目录下产生debug.o文件。标准做法是把../comm中的东西做成libcomm.a,然后用xxx_LDADD=../comm /libcomm.a加入。

xxx_LDADD=path/libyyy.a 如果xxx用到了某个lib,则用这个来指定。如果想指定全局lib则直接用LDADD=就行了。


3,三种一般需求
源代码的目录结构一般有三种:flat型,即所有的文件都在一个目录下;deep型,即顶层目录没有源文件,源文件分装在子目录如src,doc,test等;shallow型,即顶层目录中也有源文件,但大部分源文件在子目录中,例如lib,include等
第一种:
前面已经提到。
第二种:
目录结构如下:其中src中需要用到comm中的东西
test
|-- comm
| |-- debug.c
| `-- debug.h
|-- doc
| |-- test.conf
| `-- test.man.3
`-- src
|-- test.c
`-- test.h
第一步:
进入test
运行autoscan得到configure.scan
第二步:
mv configure.scan configure.in
不一样的改动是
AC_OUTPUT([Makefile comm/Makefile src/Makefile doc/Makefile])
AC_PROG_RANLIB 因为用了lib
第三步:
运行aclocal
第四步:
运行autoconf
第五步:
为每个需要Makefile的文件夹创建文件Makefile.am。这里是Makefile.am,comm/Makefile.am, src/Makefile.am,doc/Makefile.am
顶层的Makefile.am内容如下
SUBDIRS = doc comm src test 这里注意把comm放在src前面

comm/Makefile.am内容如下:
noinst_LIBRARIES=libcomm.a noinst指的是该库不要install到prefix/lib目录下,因为只是一个临时的
libcomm_a_lib=debug.h debug.c 注意命名

src/Makefile.am内容如下
bin_PROGRAMS=test
hello_SOURCES=test.h test.c

doc/Makefile.am内容如下
man_MANS=test.man.3
sysconf_DATA=test.conf

第六步:
autoheader
第七步:
automake --add-missing --copy
完成。
需要说明的是,如果还有一个目录lib里装的是一些用于做成libtest.a的文件,而且libtest.a还用到了comm中的东西,这时不 能在lib/Makefile.am中使用libtest_a_LIBADD=../comm/libcomm.a。这样回到之libtest.a中有未 解析符号,应该用libtest_a_LIBADD=../comm/debug.o(原因不明,但感觉不应该是这样的,这样太土了)

第三种:
感觉于第二种没有什么区别——直接把src目录中的东西放到顶层目录就是了。但我想应该不是如此简单。

4,结论
可以看出autoconf和automake的基本原理是先由Makefile.am提供一个Makefile的框架,然后通过 configure获取某些必要信息,如安装路径、编译器、包含的库等,并把这些信息赋给Makefile中的变量(例如LIBS、INCLUDES 等)。
重要的是很多宏的赋值,甚至还可以定义自己的宏;具体可以参考autoconf的手册。
详细情况可以参考:
autoconf手册
英文版http://www.gnu.org/software/autoconf/manual/autoconf.html
中文版http://www.linuxforum.net/books/autoconf.html
automake手册
英文版http://sources.redhat.com/automake/automake.html
中文版http://www.linuxforum.net/books/automake.html
gnu编码标准
http://www.linuxforum.net/books/gcodestd.html
<script src="http://pagead2.googlesyndication.com/pagead/show_ads.js" type="text/javascript"></script>
----
本文介绍了在 linux 系统中,通过 Gnu autoconf 和 automake 生成 Makefile 的方法。主要探讨了生成 Makefile 的来龙去脉及其机理,接着详细介绍了配置 Configure.in 的方法及其规则。

引子

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

但是如果通过查阅make的帮助文档来手工编写Makefile,对任何程序员都是一场挑战。幸而有GNU 提供的Autoconf及Automake这两套工具使得编写makefile不再是一个难题。

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

 




回页首


模拟需求

假设源文件按如下目录存放,如图1所示,运用autoconf和automake生成makefile文件。


图 1文件目录结构
图 1文件目录结构

假设src是我们源文件目录,include目录存放其他库的头文件,lib目录存放用到的库文件,然后开始按模块存放,每个模块都有一个对应的目 录,模块下再分子模块,如apple、orange。每个子目录下又分core,include,shell三个目录,其中core和shell目录存 放.c文件,include的存放.h文件,其他类似。

样例程序功能:基于多线程的数据读写保护(联系作者获取整个autoconf和automake生成的Makefile工程和源码,E-mail:normalnotebook@126.com )。

 




回页首


工具简介

所必须的软件:autoconf/automake/m4/perl/libtool(其中libtool非必须)。

autoconf是一个用于生成可以自动地配置软件源码包,用以适应多种UNIX类系统的shell脚本工具,其中autoconf需要用到 m4,便于生成脚本。automake是一个从Makefile.am文件自动生成Makefile.in的工具。为了生成 Makefile.in,automake还需用到perl,由于automake创建的发布完全遵循GNU标准,所以在创建中不需要perl。 libtool是一款方便生成各种程序库的工具。

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

1) flat指的是所有文件都位于同一个目录中。

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

2) shallow指的是主要的源代码都储存在顶层目录,其他各个部分则储存在子目录中。

就是主要源文件在当前目录中,而其它一些实现各部分功能的源文件位于各自不同的目录。automake本身就是这一类。

3) deep指的是所有源代码都被储存在子目录中;顶层目录主要包含配置信息。

就是所有源文件及自己写的头文件位于当前目录的一个子目录中,而当前目录里没有任何源文件。 GNU cpio和GNU tar就是这一类。

flat类型是最简单的,deep类型是最复杂的。不难看出,我们的模拟需求正是基于第三类deep型,也就是说我们要做挑战性的事情:)。注:我们的测试程序是基于多线程的简单程序。

 




回页首


生成 Makefile 的来龙去脉

首先进入 project 目录,在该目录下运行一系列命令,创建和修改几个文件,就可以生成符合该平台的Makefile文件,操作过程如下:

1) 运行autoscan命令

2) 将configure.scan 文件重命名为configure.in,并修改configure.in文件

3) 在project目录下新建Makefile.am文件,并在core和shell目录下也新建makefile.am文件

4) 在project目录下新建NEWS、 README、 ChangeLog 、AUTHORS文件

5) 将/usr/share/automake-1.X/目录下的depcomp和complie文件拷贝到本目录下

6) 运行aclocal命令

7) 运行autoconf命令

8) 运行automake -a命令

9) 运行./confiugre脚本

可以通过图2看出产生Makefile的流程,如图所示:


图 2生成Makefile流程图
图 2生成Makefile流程图




回页首


Configure.in的八股文

当我们利用autoscan工具生成confiugre.scan文件时,我们需要将confiugre.scan重命名为confiugre.in文件。confiugre.in调用一系列autoconf宏来测试程序需要的或用到的特性是否存在,以及这些特性的功能。

下面我们就来目睹一下confiugre.scan的庐山真面目:

 

# Process this file with autoconf to produce a configure script.
AC_PREREQ(2.59)
AC_INIT(FULL-PACKAGE-NAME, VERSION, BUG-REPORT-ADDRESS)
AC_CONFIG_SRCDIR([config.h.in])
AC_CONFIG_HEADER([config.h])
# Checks for programs.
AC_PROG_CC
# Checks for libraries.
# FIXME: Replace `main' with a function in `-lpthread':
AC_CHECK_LIB([pthread], [main])
# Checks for header files.
# Checks for typedefs, structures, and compiler characteristics.
# Checks for library functions.
AC_OUTPUT

 

每个configure.scan文件都是以AC_INIT开头,以AC_OUTPUT结束。我们不难从文件中看出confiugre.in文件的一般布局:

 

AC_INIT
测试程序
测试函数库
测试头文件
测试类型定义
测试结构
测试编译器特性
测试库函数
测试系统调用
AC_OUTPUT

 

上面的调用次序只是建议性质的,但我们还是强烈建议不要随意改变对宏调用的次序。

现在就开始修改该文件:

 

$mv configure.scan configure.in
$vim configure.in

 

修改后的结果如下:

 

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

AC_PREREQ(2.59)
AC_INIT(test, 1.0, normalnotebook@126.com)
AC_CONFIG_SRCDIR([src/ModuleA/apple/core/test.c])
AM_CONFIG_HEADER(config.h)
AM_INIT_AUTOMAKE(test,1.0)

# Checks for programs.
AC_PROG_CC
# Checks for libraries.
# FIXME: Replace `main' with a function in `-lpthread':
AC_CHECK_LIB([pthread], [pthread_rwlock_init])
AC_PROG_RANLIB
# Checks for header files.
# Checks for typedefs, structures, and compiler characteristics.
# Checks for library functions.
AC_OUTPUT([Makefile
src/lib/Makefile
src/ModuleA/apple/core/Makefile
src/ModuleA/apple/shell/Makefile
])

 

其中要将AC_CONFIG_HEADER([config.h])修改为:AM_CONFIG_HEADER(config.h), 并加入AM_INIT_AUTOMAKE(test,1.0)。由于我们的测试程序是基于多线程的程序,所以要加入AC_PROG_RANLIB,不然运行automake命令时会出错。在AC_OUTPUT输入要创建的Makefile文件名。

由于我们在程序中使用了读写锁,所以需要对库文件进行检查,即AC_CHECK_LIB([pthread], [main]),该宏的含义如下:


其中,LIBS是link的一个选项,详细请参看后续的Makefile文件。由于我们在程序中使用了读写锁,所以我们测试pthread库中是否存在pthread_rwlock_init函数。

由于我们是基于deep类型来创建makefile文件,所以我们需要在四处创建Makefile文件。即:project目录下,lib目录下,core和shell目录下。

Autoconf提供了很多内置宏来做相关的检测,限于篇幅关系,我们在这里对其他宏不做详细的解释,具体请参看参考文献1和参考文献2,也可参看autoconf信息页。

 




回页首


实战Makefile.am

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

表一列出了可执行文件、静态库、头文件和数据文件,四种书写Makefile.am文件个一般格式。


表 1Makefile.am一般格式
表 1Makefile.am一般格式

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

Makefile.am还提供了一些全局变量供所有的目标体使用:


表 2 Makefile.am中可用的全局变量
表 2 Makefile.am中可用的全局变量

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


表 3Makefile.am中可用的路径变量
表 3Makefile.am中可用的路径变量

在上文中我们提到过安装路径,automake设置了默认的安装路径:

1) 标准安装路径

默认安装路径为:$(prefix) = /usr/local,可以通过./configure --prefix=<new_path>的方法来覆盖。

其它的预定义目录还包括:bindir = $(prefix)/bin, libdir = $(prefix)/lib, datadir = $(prefix)/share, sysconfdir = $(prefix)/etc等等。

2) 定义一个新的安装路径

比如test, 可定义testdir = $(prefix)/test, 然后test_DATA =test1 test2,则test1,test2会作为数据文件安装到$(prefix)/ /test目录下。

我们首先需要在工程顶层目录下(即project/)创建一个Makefile.am来指明包含的子目录:

 

SUBDIRS=src/lib src/ModuleA/apple/shell src/ModuleA/apple/core 
CURRENTPATH=$(shell /bin/pwd)
INCLUDES=-I$(CURRENTPATH)/src/include -I$(CURRENTPATH)/src/ModuleA/apple/include
export INCLUDES

 

由于每个源文件都会用到相同的头文件,所以我们在最顶层的Makefile.am中包含了编译源文件时所用到的头文件,并导出,见蓝色部分代码。

我们将lib目录下的swap.c文件编译成libswap.a文件,被apple/shell/apple.c文件调用,那么lib目录下的Makefile.am如下所示:

 

noinst_LIBRARIES=libswap.a
libswap_a_SOURCES=swap.c
INCLUDES=-I$(top_srcdir)/src/includ

 

细心的读者可能就会问:怎么表1中给出的是bin_LIBRARIES,而这里是noinst_LIBRARIES?这是因为如果只想编译,而不想 安装到系统中,就用noinst_LIBRARIES代替bin_LIBRARIES,对于可执行文件就用noinst_PROGRAMS代替 bin_PROGRAMS。对于安装的情况,库将会安装到$(prefix)/lib目录下,可执行文件将会安装到${prefix}/bin。如果想安 装该库,则Makefile.am示例如下:

 

bin_LIBRARIES=libswap.a
libswap_a_SOURCES=swap.c
INCLUDES=-I$(top_srcdir)/src/include
swapincludedir=$(includedir)/swap
swapinclude_HEADERS=$(top_srcdir)/src/include/swap.h

 

最后两行的意思是将swap.h安装到${prefix}/include /swap目录下。

接下来,对于可执行文件类型的情况,我们将讨论如何写Makefile.am?对于编译apple/core目录下的文件,我们写成的Makefile.am如下所示:

 

noinst_PROGRAMS=test
test_SOURCES=test.c
test_LDADD=$(top_srcdir)/src/ModuleA/apple/shell/apple.o $(top_srcdir)/src/lib/libswap.a
test_LDFLAGS=-D_GNU_SOURCE
DEFS+=-D_GNU_SOURCE
#LIBS=-lpthread

 

由于我们的test.c文件在链接时,需要apple.o和 libswap.a文件,所以我们需要在test_LDADD中包含这两个文件。对于Linux下的信号量/读写锁文件进行编译,需要在编译选项中指明 -D_GNU_SOURCE。所以在test_LDFLAGS中指明。而test_LDFLAGS只是链接时的选项,编译时同样需要指明该选项,所以需要 DEFS来指明编译选项,由于DEFS已经有初始值,所以这里用+=的形式指明。从这里可以看出,Makefile.am中的语法与Makefile的语 法一致,也可以采用条件表达式。如果你的程序还包含其他的库,除了用AC_CHECK_LIB宏来指明外,还可以用LIBS来指明。

如果你只想编译某一个文件,那么Makefile.am如何写呢?这个文件也很简单,写法跟可执行文件的差不多,如下例所示:

 

noinst_PROGRAMS=apple
apple_SOURCES=apple.c
DEFS+=-D_GNU_SOURCE

 

我们这里只是欺骗automake,假装要生成apple文件,让它为我们生成依赖关系和执行命令。所以当你运行完automake命令后,然后修改apple/shell/下的Makefile.in文件,直接将LINK语句删除,即:

 

…….
clean-noinstPROGRAMS:
-test -z "$(noinst_PROGRAMS)" || rm -f $(noinst_PROGRAMS)
apple$(EXEEXT): $(apple_OBJECTS) $(apple_DEPENDENCIES)
@rm -f apple$(EXEEXT)
#$(LINK) $(apple_LDFLAGS) $(apple_OBJECTS) $(apple_LDADD) $(LIBS)
…….

 

通过上述处理,就可以达到我们的目的。从图1中不难看出为什么要修改Makefile.in的原因,而不是修改其他的文件。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值