使用autotools工具集生成Makefile文件

一、前言

Makefile是用于自动编译和链接的,一个工程有很多文件组成,每一个文件的改变都会导致工程的重新链接,但是不是所有文件都需要重新编译,Makefile中记录着文件的信息,在make的时候就会决定在链接的时候需要重新编译哪些文件。

Makefile的宗旨就是让编译器知道编译一个文件需要依赖其他哪些文件。当依赖文件有了改变,编译器会自动检测到之前的文件已经过时,进而重新编译相应的模块。

本文将介绍使用autotools工具集生成符合Linux规范的Makefile文件。

二、安装工具集

autotools是一个系列工具,包含了以下软件:

aclocal autoscan autoconf autoheader automake etc.

通常在安装以上某一个软件后,就会自动安装autotools系列工具,所以执行以下命令即可安装,但也要注意查缺补漏。网上也有较多手动安装的教程,可自行了解。

sudo apt-get install autoconf

三、入门使用

下图为使用autotools工具集生成Makefile的流程图:
使用autotools工具集生成Makefile文件_第1张图片

根据流程图我们来实现编译一个hello world程序。

// hello.cc
#include 

int main()
{
    std::cout << "Hello World!" << std::endl;
}

首先进入项目根目录,执行autoscan,在当前目录下会生成configure.scan文件。
autoscan
我们需要将confiugre.scan重命名为confiugre.in文件(.in后缀为旧写法,执行命令时可能会报错,这里建议改成.ac后缀)。confiugre.ac调用一系列autoconf宏来测试程序需要的或用到的特性是否存在,以及这些特性的功能。

#                                               -*- 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([hello.cc])
AC_CONFIG_HEADERS([config.h])

# Checks for programs.
AC_PROG_CXX

# Checks for libraries.

# Checks for header files.

# Checks for typedefs, structures, and compiler characteristics.

# Checks for library functions.

AC_OUTPUT

AC_INIT总是configure.ac中的第一个宏。它扩展为许多可由其他configure脚本共享的模板文件代码。这些代码解析传到 configure中的命令行参数。这个宏的一个参数是一个文件名,这个文件应该在源代码目录中,它用于健全性检查,以保证configure脚本已正确定位源文件目录。

AC_OUTPUT列出由configure脚本创建的文件。这些文件都是由带.in后缀的同名文件生成的。例如Makefile是由Makefile.in生成的。在执行AC_OUTPUT宏时,configure脚本处理包含有两个@符号标志的变量的文件。只有用AC_SUBST输出了变量,它才能识别这些变量。这些特征用于将一个Makefile.in文件转换成一个Makefile文件。典型情况下,Makefile.in是由automake从Makefile.am生成的。

不过,你可以只用autoconf,而不用automake,自己编写一个 Makefile.in文件。

修改configure.ac,增加AM_INIT_AUTOMAKE以及在AC_OUTPUT中列出输出文件Makefile。修改后,内容如下:

#                                               -*- 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([hello.cc])
AC_CONFIG_HEADERS([config.h])

# Checks for programs.
AC_PROG_CXX

# Checks for libraries.

# Checks for header files.

# Checks for typedefs, structures, and compiler characteristics.

# Checks for library functions.

AC_OUTPUT([Makefile])

接着依次执行以下命令,生成configure文件:

aclocal
autoconf
autoheader

新增文件如下:
使用autotools工具集生成Makefile文件_第2张图片
然后在根目录下新建一个Makefile.am文件,指定编译的源文件以及编译目标等。

AUTOMAKE_OPTIONS = foreign
bin_PROGRAMS = hello
hello_SOURCES = hello.cc

此处规定了生成命名为hello的可执行文件,源文件是hellc.cc。

AUTOMAKE_OPTIONS是automake的选项。automake主要是帮助开发GNU软件的人员来维护软件,所以在执行automake时,会检查目录下是否存在标准GNU软件中应具备的文件,例如NEWS、AUTHOR、ChangeLog等文件。设置为foreign时,automake会改用一般软件的标准来检查。如果不加这句的话,需要在autoconf之前,先执行以下命令来生成NEWS、AUTHOR、ChangeLog等文件。

touch NEWS README AUTHORS ChangeLog

保存后,执行automake生成Makefile.in文件:

automake --add-missing

最后使用./configure和make命令,就可以生成一个可执行文件hello,执行./hello会在终端输出“Hello World!”。
使用autotools工具集生成Makefile文件_第3张图片

四、Makefile.am编写规则

Makefile实质上就是target/dependencies/action三者所组成的一连串规则。make命令会根据Makefile的规则来决定如何编译和连接程式。而automake则主要通过编辑Makefile.am来控制以上行为。

Makefile.am共有5类规则,如下表:

文件类型 书写格式
可执行文件 bin_PROGRAMS = foo
foo_SOURCES = xxx.c xxxx.c
foo_LDADD =
foo_LDFLAGS =
foo_DEPENDENCIES =
静态库 lib_LIBRARIES = foo.a
foo_a_SOURCES = xxx.c xxxx.c
foo_a_LDADD =
foo_a_LIBADD =
foo_a_LDFLAGS =
动态库 lib_LIBRARIES = foo.la
foo_la_SOURCES = xxx.c xxxx.c
foo_la_LDADD =
foo_la_LIBADD =
foo_la_LDFLAGS =
头文件 include_HEADERS = foo.h
noinst_HEADERS = foo2.h
数据文件 data_DATA = data1 data2

其中,生成动态库的同时还会自动生成一个静态库,所以在一般情况下都不直接使用静态库规则。

Makefile.am中还有一些可以直接使用的全局变量,表示所有目标所共享的一些属性,见下表:

变量 含义
INCLUDES 编译时所需头文件
LDADD 编译时所需链接的库文件
LDFLAGS 编译时的选项
AM_CXXFLAGS 编译C++文件的选项
AM_CFLAGS 编译C文件的选项
EXTRA_DIST 除源代码和一些默认文件以外,其它需要打包的文件
SUBDIRS 在处理本目录之前要递归处理的子目录
top_srcdir 项目源码的顶层目录
top_builddir 项目目标文件的最顶层目录

在上面的例子中,我们展示了如何编写生成执行文件的规则,接下来以Faac开源库的Makefile.am为例,分析生成动态库规则的写法。以下是libfaac目录下的Makefile.am的部分内容:

common_SOURCES = bitstream.c fft.c frame.c blockswitch.c util.c channels.c filtbank.c tns.c quantize.c huff2.c huffdata.c stereo.c
common_INCLUDES = channels.h filtbank.h blockswitch.h coder.h frame.h tns.h bitstream.h fft.h util.h quantize.h huffdata.h huff2.h stereo.h
common_LIBADD = -lm
common_CFLAGS = -fvisibility=hidden

lib_LTLIBRARIES = libfaac.la
libfaac_la_SOURCES = ${common_SOURCES} ${common_INCLUDES}
libfaac_la_LIBADD = ${common_LIBADD}
libfaac_la_CFLAGS = ${common_CFLAGS}

lib_LTLIBRARIES表示了生成的库文件,名为libfaac,后续的规则编写需要带上libfaac前缀。la文件是使用libtool编译出来的库文件,其实是个文本文件,记录同名动态库和静态库的相关信息。执行make install之后,会在/usr/local/lib目录下生成相关库文件。如果不想安装在系统中,则可使用noinst_LTLIBRARIES代替lib_LTLIBRARIES,不需执行make install。

libfaac_la_SOURCES代表了生成库所需要的源文件。

libfaac_la_LIBADD表示编译依赖的库文件。

libfaac_la_CFLAGS表示用于C编译器的选项。

以上只是部分规则的基础使用,更多详细内容可以查看GUN的automake文档。

五、更改库安装路径

automake设置了默认的安装路径为:

$(prefix) = /usr/local

bindir = $(prefix)/bin,
libdir = $(prefix)/lib,
datadir = $(prefix)/share,
sysconfdir = $(prefix)/etc

一般make install之后生成的库,会安装在/usr/local/lib下。如果想要修改安装路径,可以执行./configure命令时增加–prefix选项设置新的路径。

./configure --prefix=YOUR_NEW_PATH

以上是关于使用autotools工具集生成Makefile文件的分享,好好学习,天天向上。

你可能感兴趣的:(c)