1、概述
什么是makefile?或许很多Winodws的程序员都不知道这个东西,因为那些Windows的IDE都为你做了这个工作,但我觉得要作一个好的和professional的程序员,makefile还是要懂。这就好像现在有这么多的HTML的编辑器,但如果你想成为一个专业人士,你还是要了解HTML的标识的含义。特别在Unix下的软件编译,你就不能不自己写makefile了,会不会写makefile,从一个侧面说明了一个人是否具备完成大型工程的能力。因为,makefile关系到了整个工程的编译规则。一个工程中的源文件不计数,其按类型、功能、模块分别放在若干个目录中,makefile定义了一系列的规则来指定,哪些文件需要先编译,哪些文件需要后编译,哪些文件需要重新编译,甚至于进行更复杂的功能操作,因为makefile就像一个Shell脚本一样,其中也可以执行操作系统的命令。 makefile带来的好处就是——“自动化编译”,一旦写好,只需要一个make命令,整个工程完全自动编译,极大的提高了软件开发的效率。make是一个命令工具,是一个解释makefile中指令的命令工具,一般来说,大多数的IDE都有这个命令,比如:Delphi的make,Visual C++的nmake,Linux下GNU的make。可见,makefile都成为了一种在工程方面的编译方法。
我相信所有在Unix/Linux下编写过C/C++程序都遇到或使用过Makefile,使用make编译程序相当简单,但是使用make来开发程序却不那么简单。对于一个程序,Makefile小则几百行多则上万行,这对于程序员来说是一件相当痛苦的事情。为此GNU提供Autoconf、Automake两个软件来自动生成Makefile文件,这个程序员提供了很大的方便。
2、准备工作
首先要确认已安装一下软件:
a) GNU autoconf
b) GNU automake
c) GNU m4
d) GNU libtool
3、一个简单的例子
a)创建目录
mkdir hello
cd hello/
mkdir src
b)在src目录编写源代码hello.c
源代码如下:
#include
int main(int argc , char **argv)
{
printf("Hello,world!\n");
return0;
}
c)编写Makefile.am文件
在src目录下编写Makefile.am文件:
AUTOMAKE_OPTIONS = foreign
bin_PROGRAMS = hello
hello_SOURCES = hello.c
hello_LDADD = -lpthread (这里只是为了测试,实际不需要)
退到hello目录下编写Makefile.am文件:
AUTOMAKE_OPTIONS=foreign
SUBDIRS = src
e) autoscan并修改configure.in
执行autoscan命令,生成configure.scan文件,将其更名为configure.in,并修改其内容:
# -*- Autoconf -*-
# Process this file with autoconf toproduce a configure script.
AC_PREREQ([2.68])
AC_INIT([FULL-PACKAGE-NAME],[VERSION], [BUG-REPORT-ADDRESS])
AM_INIT_AUTOMAKE(hello,1.0)
AC_CONFIG_SRCDIR([src/hello.c])
#AC_CONFIG_HEADERS([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, andcompiler characteristics.
# Checks for library functions.
#AC_CONFIG_FILES([Makefile
# src/Makefile])
AC_OUTPUT(Makefile
src/Makefile)
f) aclocal
生成aclocal.m4和autom4te.cache文件。
g) autoconf
根据 configure.in和aclocal.m4生成configure文件
h) automake --add-missing
通过Makefile.am文件生成Makefile.in文件,并生成install-sh,depcomp,INSTALL,missing等文件。
i) ./configure
通过Makefile.in文件生成Makefile文件。
解释:
AM_INIT_AUTOMAKE([FULL-PACKAGE-NAME],[VERSION], [BUG-REPORT-ADRESS]):
这个是使用Automake 所必备的宏,FULL-PACKAGE-NAME 是所要产生软件的名称,VERSION 是版本编号,BUG-REPORT-ADRESS反馈地址。
AC_PROG_CC:
检查系统可用的C 编译器,若源代码是用C 写的就需要这个宏
AC_OUTPUT(file):
设置configure 所要产生的文件,若是Makefile ,configure 便会把它检查出来的结果填充到Makefile.in 文件后产生合适的Makefile。
AUTOMAKE_OPTIONS:
设置Automake 的选项。Automake 主要是帮助开发GNU 软件的人员来维护软件,所以在执行Automake 时,会检查目录下是否存在标准GNU 软件中应具备的文件,例如'NEWS'、'AUTHOR'、'ChangeLog'、’README’ 等文件。设置为foreign 时,Automake 会改用一般软件的标准来检查。
bin_PROGRAMS:
定义要产生的执行文件名。如果要产生多个执行文件,每个文件名用空白符隔开。
hello_SOURCES:
生成这个可执行文件所需要的源文件。
hello_LDADD:
链接库文件。
4、深度了解如何生成Makefile文件
a) autoscan (autoconf)
扫描源代码以搜寻普通的可移植性问题,比如检查编译器,库,头文件等,生成文件configure.scan,它是configure.ac的一个雏形。
your source files --> [autoscan*] -->[configure.scan] --> configure.ac
b) aclocal (automake)
根据已经安装的宏,用户定义宏和acinclude.m4文件中的宏将configure.ac文件所需要的宏集中定义到文件 aclocal.m4中。
aclocal是一个perl 脚本程序,它的定义是:“aclocal- create aclocal.m4 by scanning configure.ac”
c) autoheader(autoconf)
根据configure.ac中的某些宏,比如cpp宏定义,运行m4,声称config.h.in
d) automake
automake将Makefile.am中定义的结构建立Makefile.in,然 后configure脚本将生成的Makefile.in文件转换 为Makefile。如果在configure.ac中定义了一些特殊的宏,比如AC_PROG_LIBTOOL,它会调用libtoolize,否则它 会自己产生config.guess和config.sub
e) autoconf
将configure.ac中的宏展开,生成configure脚本。这个过程可能要用到aclocal.m4中定义的宏。
f) ./configure的过程
g) make过程
5、使用automake及autoconf制作静态库文件
a) 目录结构如下:
example
|——src 目录(存放源代码文件)
|——hello.c
|——lib 目录(存放用来生成库的文件)
|——test.c 用来生成静态库libhello.a
|——include 目录(存放程序中使用的头文件)
|——hello.h
b) 编写各个源文件
hello.h文件:
extern void print(char *);
test.c文件:
#include
void print(char *msg)
{
printf("%s\n",msg);
}
hello.c文件:
#include "hello.h"
int main()
{
print("helloworld!\n");
return0;
}
c) 编写各个Makfile.am文件:
Makefile.am文件:
SUBDIRS=lib src
lib/Makefile.am文件:
noinst_LIBRARIES=libhello.a
libhello_a_SOURCES=test.c
src/Makefile.am文件:
INCLUDES=-I ../include
bin_PROGRAMS=hello
hello_SOURCES=hello.c
hello_LDADD=../lib/libhello.a
解释:
SUBDIRS:
表示子目录下也有Makefile.am文件。
noinst_LIBRARIES :
noinst 表示生成的是静态库,不需要makeinstall ,直接制定它的位置和名字就
可以使用。
libhello_a_SOURCES:
表示用来生成静态库的源文件
d) 生成并修改configure.in
执行autoscan,生成configure.scan,将其更名为configure.in,并修改。修改和上面所说基本相同,不同的是添加了一行:AC_PROG_RANLIB。
# -*- Autoconf -*-
# Process this file with autoconf toproduce a configure script.
AC_PREREQ([2.68])
#AC_INIT([FULL-PACKAGE-NAME], [VERSION],[BUG-REPORT-ADDRESS])
AC_INIT(hello,1.1,[email protected])
AM_INIT_AUTOMAKE
AC_CONFIG_SRCDIR([src/hello.c])
AC_CONFIG_HEADERS([config.h])
# Checks for programs.
AC_PROG_CC
# Checks for libraries.
AC_PROG_RANLIB
# Checks for header files.
# Checks for typedefs, structures, andcompiler characteristics.
# Checks for library functions.
#AC_CONFIG_FILES([Makefile
# lib/Makefile
# src/Makefile])
AC_OUTPUT(Makefile
lib/Makefile
src/Makefile)
e) 生成configure文件及生成Makefile文件
执行以下命令:
touch NEWS README AUTHORS ChangeLog
autoreconf -fvi
./configure
make
6、使用automake及autoconf制作动态库文件
动态库和静态库的区别在于:动态库是在程序装载的时候才加入到程序。
a) 目录结构
example
|——src 目录(存放源代码文件)
|——hello.c
|——lib 目录(存放用来生成库的文件)
|——test.c 用来生成静态库libhello.a
|——include 目录(存放程序中使用的头文件)
|——hello.h
b) 编写各个源文件
hello.h文件:
extern void print(char *);
test.c文件:
#include
void print(char *msg)
{
printf("%s\n",msg);
}
hello.c文件:
#include "hello.h"
int main()
{
print("helloworld!\n");
return0;
}
c) 编写各个Makfile.am文件:
Makefile.am文件:
AUTOMAKE_OPTIONS =foreign
SUBDIRS=lib src
lib/Makefile.am文件:
AUTOMAKE_OPTIONS = foreign
lib_LTLIBRARIES = libhello.la
libhello_la_SOURCES = test.c
src/Makefile.am文件:
AUTOMAKE_OPTIONS = foreign
INCLUDES = -I../include
bin_PROGRAMS = hello
hello_SOURCES = hello.c
hello_LDADD = -lhello
d) 生成并修改configure.in
执行autoscan,生成configure.scan,将其更名为configure.in,并修改。configure.in大致和上面相同,只是在其中加入了AC_PROG_LIBTOOL,修改后如下:
# -*- Autoconf -*-
# Process this file with autoconf toproduce a configure script.
AC_PREREQ([2.68])
#AC_INIT([FULL-PACKAGE-NAME], [VERSION],[BUG-REPORT-ADDRESS])
AC_INIT(hello,1.0,[email protected])
AM_INIT_AUTOMAKE
AC_CONFIG_SRCDIR([src/hello.c])
#AC_CONFIG_HEADERS([config.h])
# Checks for programs.
AC_PROG_CC
AC_PROG_LIBTOOL
# Checks for libraries.
# Checks for header files.
# Checks for typedefs, structures, andcompiler characteristics.
# Checks for library functions.
AC_CONFIG_FILES([Makefile
lib/Makefile
src/Makefile])
AC_OUTPUT
e) 生成configure文件及Makefile文件并编译
依次执行以下命令:
aclocal
libtoolize -f -c
autoconf
automake --add-missing
./configure
make
注:libtoolize 提供了一种标准的方式来将libtool 支持加入一个软件包,而GNU libtool 是
一个通用库支持脚本,将使用动态库的复杂性隐藏在统一、可移植的接口中。