automake 使用指南

在构建大型的C/C++项目时,往往需要借助Makefile. 然而手动编写makefile是相当复杂的,这一点在程序需要跨平台的时候表现地更为明显。在此背景下,我们需要借助于一些自动化的工具来生成Makefile和configure。本文主要介绍autoconf, automake等自动化工具,默认读者已经具备linux shell脚本和makefile的基础知识。

1. 工具准备

autoconf,automake,libtool等工具

2. 实例一

目前automake支持三种目录层次:flat、shallow和deep。
* flat(平),指的是所有文件都位于同一个目录中,就是所有源文件、头文件以及其他库文件都位于当前目录中,且没有子目录。Termutils就是这一类。
* shallow(浅),指的是主要的源代码都储存在顶层目录,其他各个部分则储存在子目录中,就是主要源文件在当前目录中,而其它一些实现各部分功能的源文件位于各自不同的目录。automake本身就是这一类。
* deep(深),指的是所有源代码都被储存在子目录中;顶层目录主要包含配置信息

2.1 初始文件模板与源程序

先来看看整个project的构成:其中源程序文件有三个test.c , test.h, main.c ,其他的文件是我们在编译过程中自动和手动生成的。

|-- Makefile.am
|-- configure.ac
|-- lib
|   |-- test.c
|   `-- test.h
`-- main
    |-- Makefile.am
    `-- main.c

与Makefile和configure有关的配置文件我们放在后面介绍,这里给出工程文件的相关code。

/* project/main.c */
#include <stdio.h>
#include "test.h"
int main()
{
    printf("main entrance.\n");
    test_method();
    return 0;
}

/* project/lib/test.c */
#include <stdio.h>
#include "../include/test.h"
void test_method()
{
    printf("test method.\n");
}

//test.h
void test_method();

现在我们的目的是根据模板来生成Makefile文件;这个流程,我们可以用这样一张图表示
这里写图片描述
从这张图,我们可以看到,我们需要手动编写的有两个文件:Makefile.am && configure.in;

2.2 生成configure模板configure.in

$ autoscan

这条命令,会根据当前目录下地源程序结构,生成对应的configure.scan模板,根据这个文件,修改成configure文件模板,configure.in,这个文件是生成configure文件的基础。如果我们需要定义一些configure的具体参数,那么我们需要更改这个模板。实际上在大型项目的构建过程中,这个文件正是初始的几个需要手动编写的文件之一。如何编写configure.in文件,我们将在其他地方说明。

#config.scan                                               -*- 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([lib/test.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_CONFIG_FILES([Makefile
                 main/Makefile])
AC_OUTPUT

将上述文件进行改动如下:

//config.in
#                                               -*- Autoconf -*-
# Process this file with autoconf to produce a configure script.
AC_PREREQ([2.69])
AC_INIT([FULL-PACKAGE-NAME], [VERSION], [BUG-REPORT-ADDRESS])
AM_INIT_AUTOMAKE
AC_CONFIG_SRCDIR([lib/test.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_CONFIG_FILES([Makefile
                 main/Makefile])
AC_OUTPUT

2.3 生成configure文件

执行命令aclocal和autoconf,分别会产生aclocal.m4及configure两个文件。

$aclocal
$autoconf

2.4 新建Makefile.am

automake将根据Makefile.am生成Makefile.in.从上面的目录结构中,我们可以看到,这个项目中含有两个Makefile.am,第一个在root目录,第二个在main目录。内容分别如下:

ykhuang@ubuntu:/tmp/project$ cat Makefile.am
AUTOMAKE_OPTIONS = foreign
SUBDIRS = main

ykhuang@ubuntu:/tmp/project$ cat main/Makefile.am
AM_CPPFLAGS = -I$(top_srcdir)/lib
noinst_PROGRAMS= main
main_SOURCES = $(top_builddir)/lib/test.c\
                           $(top_builddir)/main/main.c

Makefile.am是整个流程中的关键,详细可以参考GNU 相关文档,本文也会在后续的章节中进行介绍。

2.5运行automake,根据Makefile.am生成Makefile.in

$automake

2.6执行configure, 生成Makefile

$configure

3. configure.in的编写规则

configure.in的模板形式如下:

#                                               -*- Autoconf -*-
# Process this file with autoconf to produce a configure script.
AC_PREREQ([2.69])
AC_INIT([FULL-PACKAGE-NAME], [VERSION], [BUG-REPORT-ADDRESS])
AM_INIT_AUTOMAKE
AC_CONFIG_SRCDIR([config.h.in])
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_CONFIG_FILES([Makefile
                 main/Makefile])
AC_OUTPUT

Autoconf提供了各种内置的宏,用于检测;AM_INIT_AUTOMAKE && AC_CONFIG_FILES 是两个我们需要的手动加入和编写的宏定义。

4. Makefile.am 编写规则

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

|文件|格式|
|可执行文件|test|

文件 格式
可执行文件 bin_PROGRAMS = foo
所有*.c文件将被编译成一个目标文件,最后链接成一个可执行文件 foo_SOURCES = foo.c func.c
foo_LDADD =
foo_LDFLAGS =
foo_DEPENDENCIES =
静态库 lib_LIBRARIES = foo.a
foo_a_SOURCES = foo.c func.c
foo_a_LDADD =
foo_a_LDFLAGS =
foo_a_DEPENDENCIES

对于可执行文件和静态库类型,如果只想编译,不想安装到系统中,可以用noinst_PROGRAMS代替bin_PROGRAMSnoinst_LIBRARIES代替lib_LIBRARIES。同时,这些书写规则都是局部的,仅仅对一个目标起作用。Makefile.am还有一些全局变量,能够作用于所有规则.

全局变量 含义
AM_CPPFLAGS 编译器的-I参数
SUBDIRS 在处理顶层目录之前,先递归处理子目录

系统预定义的两个基本路径

路径名称 含义
$(top_srcdir) 源代码所在目录
$(top_builddir) 编译顶层目录

4.1 在srcdir之外编译文件

在很多情况下,我们并不需要源代码目录和编译目录相同,假设编译顶层目录是build,那么此时我们在build目录下运行configure脚本,就能生成对应Makefile文件,然后运行相关命令即可。具体可以参考GNU相关文档的VPATH章节。

参考

  1. http://www.ibm.com/developerworks/cn/linux/l-makefile/
  2. http://www.gnu.org/software/automake/manual/automake.html#Basic-Installation
阅读更多
想对作者说点什么?
相关热词

博主推荐

换一批

没有更多推荐了,返回首页