Table of Contents
1 如何自动生成Makefile
需要工具:GNU autoconf, automake, m4, perl
2 automake 支持3种目录层次结构
- flat:指所有源代码文件都存储在顶层目录中,且没有子目录。
- shallow:指主要源代码文件存储在顶层目录中,其它实现部分功能的源代码文件(主要是库)存储在子目录中。
- deep:指所有源代码文件都存储在子目录中,顶层目录不包含任何源代码文件,只包含配置信息。
3 生成Makefile的步骤
- 首先进入project工程的顶层目录;
$cd project/
- 运行autoscan命令,生成文件configure.scan;
$./autoscan
- 将configure.scan文件重命名为configure.ac(老版本使用后缀.in(已经淘汰),新版本使用.ac),并修改configure.ac文件;
$mv configure.scan configure.ac
- 运行aclocal命令;
$aclocal
- 运行autoconf命令,生成可执行文件configure;
$autoconf
- 在project顶层目录下手动新建NEWS、README、AUTHORS、ChangeLog文件,使用touch命令创建空文件即可;
$touch NEWS README AUTHORS
- 在project各层目录下根据需要新建Makefile.am文件,并编辑Makefile.am文件;
$vi Makefile.am
- 运行automake命令,利用Makefile.am文件生成Makefile.in文件;
$automake
- 运行./configure,生成makefile文件。
$./configure
4 编辑configure.ac文件
利用autoscan工具可以生成configure.scan文件,这里需要将configure.scan文件重命名为configure.ac文件。configure.ac调用一系列autoconf宏来测试程序需要的或者利用到的特性是否存在,以及这些特性的功能。configure.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([src/main.c]) AC_CONFIG_HEADERS([config.h]) # Checks for programs. AC_PROG_CC # Checks for libraries. # Checks for header files. AC_CHECK_HEADERS([stdlib.h]) # Checks for typedefs, structures, and compiler characteristics. # Checks for library functions. AC_CONFIG_FILES([common/Makefile src/Makefile]) AC_OUTPUT
每个configure.scan文件都是以AC_INIT开头,以AC_OUTPUT结束。现在开始修改configure.ac文件
$mv configure.scan configure.ac $vim configure.in
修改后的configure.ac内容如下
# -*- Autoconf -*- # Process this file with autoconf to produce a configure script. AC_PREREQ([2.61]) AC_INIT([Jupiter], [1.0], [bugs@jupiter.org]) AM_INIT_AUTOMAKE AC_CONFIG_SRCDIR([src/main.c]) AC_CONFIG_HEADERS([config.h]) # Checks for programs. AC_PROG_CC AC_PROG_RANLIB AC_PROG_INSTALL AM_PROG_CC_C_O # Checks for header files (1). AC_HEADER_STDC # Checks for command line options AC_ARG_ENABLE([async-exec], [AS_HELP_STRING([--disable-async-exec], [disable asynchronous execution @<:@default: no@:>@])], [async_exec=${enableval}], [async_exec=yes]) if test "x${async_exec}" = xyes; then have_pthreads=no AC_SEARCH_LIBS([pthread_create], [pthread], [have_pthreads=yes]) if test "x${have_pthreads}" = xyes; then AC_CHECK_HEADERS([pthread.h], [], [have_pthreads=no]) fi if test "x${have_pthreads}" = xno; then echo "---------------------------------------" echo "Unable to find pthreads on this system." echo "Building a single-threaded version. " echo "---------------------------------------" async_exec=no fi fi if test "x${async_exec}" = xyes; then AC_DEFINE([ASYNC_EXEC], 1, [async exec enabled]) fi # Checks for header files (2). AC_CHECK_HEADERS([stdlib.h]) # Checks for libraries. # Checks for typedefs, structures, and compiler characteristics. # Checks for library functions. AC_CONFIG_FILES([Makefile common/Makefile src/Makefile]) AC_OUTPUT echo \ "------------------------------------------------- ${PACKAGE_NAME} Version ${PACKAGE_VERSION} Prefix: '${prefix}'. Compiler: '${CC} ${CFLAGS} ${CPPFLAGS}' Package features: Async Execution: ${async_exec} Now type 'make @<:@<target>@:>@' where the optional <target> is: all - build all binaries install - install everything --------------------------------------------------"
5 configure.ac文件说明
- 修改AC_INIT(package_name, package_verison, owner_email)
package_name:工程名字
package_version:当前工程的版本号
owner_email:工程所有者邮箱
- 增加AM_INIT_AUTOMAKE(必须)
- 增加AC_CONFIG_FILES(Makefile, …)
指明了所有要生成的Makefile的路径,必须与工程中所有Makefile.am的路径保持一致。
- 给configure配置自定义参数
configure常用的参数格式主要有两种:–enable-xxx和–disable-xxx; –with-xxx和–with-out-xxx分别通过以下两个宏来定义这两种参数
AC_ENABLE(option-name, help-string, [action-if-given], [action-if-not-givin]) AC_ARG_WITH(option-name, help-string, [action-if-given], [action-if-not-givin])
option-name:参数名称
help-string:当执行./configure –help时,用于描述参数的帮助信息
action-if-given:当用户传递了设置的参数时,执行对应的sh脚本指令。ex:./configure –enable-xxx
action-if-not-ginven:当用户没有传递设置的参数时,执行对应的sh脚本指令。ex:./configure
下面举例说明:
AC_ARG_ENABLE([async-exec], [AS_HELP_STRING([--disable-async-exec], [disable asynchronous execution @<:@default: no@:>@])], [async_exec=${enableval}], [async_exec=yes]) if test "x${async_exec}" = xyes; then have_pthreads=no AC_SEARCH_LIBS([pthread_create], [pthread], [have_pthreads=yes]) if test "x${have_pthreads}" = xyes; then AC_CHECK_HEADERS([pthread.h], [], [have_pthreads=no]) fi if test "x${have_pthreads}" = xno; then echo "---------------------------------------" echo "Unable to find pthreads on this system." echo "Building a single-threaded version. " echo "---------------------------------------" async_exec=no fi fi if test "x${async_exec}" = xyes; then AC_DEFINE([ASYNC_EXEC], 1, [async exec enabled]) fi
定义了一个参数async-exec,当传入参数./configure –disable-async-exec时,执行async_exec=${enableval},这里介绍一下变量enableval,当传入参数时会同时给该变量赋值,如果传入参数的形式是–disabe-xxx或–without-xxx,则enableval的值为no;如果传入参数的形式是–enable-xxx或者–with-xxx,则enableval的值为yes。所以这里async_exec的值为no。当没有传输设置的参数时,即./configure,则执行[async_exec=yes]。接下来判断"x${async_exec}"的值,如果等于xyes,则执行AC_SEARCH_LIBS宏,该宏的作用是检查系统中是否存在线程库pthread。接着执行AC_CHECK_HEADERS宏,该宏的作用是检查系统中是否包含头文件pthread.h。否则打印出错信息。最后调用宏AC_DEFINE,该宏的作用是定义一个c的宏,第一个参数是宏名,第二个参数是该宏的值,第三个参数起描述作用。
6 Makefile.am文件说明
Makefile.am是一种比Makefile更高层次的规则,主要作用是指定要生成什么目标,它由什么源文件生成,要安装到什么目录等。 Makefile的一般格式
File Type | Format |
---|---|
Excutable Files | bin_PROGRAMS = foo |
foo_SOURCES = xxx.c | |
foo_LDADD = | |
foo_LDFLAGS = | |
foo_DEFENDENCIES = | |
Static Lib | lib_LIBRARIES = libfoo.a |
foo_a_SOURCES = | |
foo_a_LDADD = | |
foo_a_LIBADD = | |
foo_a_LDFLAGS = | |
Header Files | include_HEADERS = foo.h |
Data Files | data_DATA = data1 data2 |
- 可执行文件的生成
要生成一个可执行文件,需要在Makefile.am中写一套可执行文件的规则,如上表所示。这里使用源文件hello.c生成可执行文件hello,该可执行文件需要链接库libtest.so。
bin_PROGRAMS = hello hello_SOURCES = hello.c hello_LDADD = -ltest hello_LDFLAGS = -l./include
其中大写字母部分,比如_PROGRAMS被称为primary。primary表示如何处理等号后面所跟的参数,这里指hello。小写字母部分,比如bin则表示安装目录,这里生成的目标hello最后会被安装在${prefix}/bin/目录下。
- 库的生成
要生成一个库,需要在Makefile.am中加入一套动态库规则,如上表所示。这里使用源文件test1.c和test2.c生成动态库libtest.so,库的版本号为1.0.10,库需要额外链接一个叫libhello.so的库。 lib_LTLIBRARIES = test.la test_la_SOURCES = test1.c test2.c test_la_LIBADD = -lhello
hello_la_LDFLAGES = -version-info 1.0.10 指定库的版本信息,其它参数 -avoid-version 生成不带版本号的库 -all-static 生成静态库
对于可执行文件和静态库类型,如果只想编译,不想安装到系统中,可以用noinst_PROGRAMS代替bin_PROGRAMS,noinst_LIBRARIES代替lib_LIBRARIES。
Makefile.am中可用的全局变量
Variables | 含义 |
---|---|
INCLUDES | 比如链接时所需要的头文件 |
LDADD | 比如链接时所需要的库文件 |
LDFLAGS | 比如链接时所需要的库文件选项标志 |
EXTRA_DIST | 源程序和一些默认的文件将自动打入.tar.gz包 |
其它文件若要进入.tar.gz包,则使用这种方法 | |
SUBDIRS | 在处理本目录之前要递归处理哪些子目录 |
参考资料: