基本流程

基本流程为:

  1. 使用autoscan生成configure.scan文件,然后重命名为configure.ac
    configure.ac里面包含一些自动检查的内容
  2. 执行aclocal,configure.ac中的宏实际上是m4宏的一个封装,这条命令将会吧ac宏解析成m4宏
  3. 执行autoconf, 它会生成configure脚本
  4. 执行autoheader,它会根据configure.ac中的内容生成一些预定义信息
  5. Makefile.am中包含了程序编译链接信息,也就是makefile的主体内容,执行automake会生成Makefile的前置文件
  6. 执行./configure会生成Makefile文件

configure是检查系统设置,库函数是否满足等运行环境判断,Makefile.am则是真正的进行编译

configure.ac

autoconf基于此

首先介绍m4,m4是一个宏处理器,它会扫描文本,如果遇到宏则将其展开。

我们可以简单的认为他将shell脚本套上了一层函数的壳,例如:

// 检测是否安装foo程序的shell
if [ $(which foo) ]
then
echo "checking foo ... yes!"
else
echo "You should install foo!"
exit -1
fi

// check-foo.m4中脚本为
define(`check-foo', `
if [ $(which foo) ]
then
echo "checking foo ... yes!"
else
echo "You should install foo!"
exit -1
fi
')

然后在configure.ac中使用include(check-foo.m4),再运行m4 configure.ac就可以在生成文件中得到这个宏的展开结果

而autoconf其实是给m4套上了一层外壳,例如:

将check-foo.m4中文件内容修改为
AC_DEFUN([CHECK_FOO],
[if {% post_link $(which foo) %}
then
echo "checking foo ... yes!"
else
echo "You should install foo!"
exit -1
fi])

然后将configure.ac中的内容修改为:

AC_INIT
CHECK_FOO

运行下面命令
aclocal -I m4 // check-foo.m4在m4目录中
autoconf
./configure

如果系统中没有foo则会提示

which: no foo in (/bin:/usr/bin:/usr/local/bin)
You should install foo!

也就是说autoconf时自动将CHECK_FOO宏展开,而aclocal则是在本地文件中扫描是否有configure.ac中定义的宏

常用的autoconf宏

宏名 格式 说明
AC_PREREQ (version) 确定autoconf版本,它是在AC_INIT前唯一使用的宏
AC_INIT (package,version,[bug-report],[tarname],[url]) 默认生成的文件打包名为: tarname-version.tar.gz
AC_SUBST AC_SUBST(GLIB2_CFLAGS) 输出能被Makefile.am使用的变量
AC_ARG_ENABLE AC_ARG_ENABLE([gstaudio],AS_HELP_STRING([—enable-gstaudio=@:@yes/auto/no@:@], [Enable the GStreamer 1.0 audio backend @:@default=auto@:@]),[],[enable_gstaudio=”auto”]) 为configure添加—XX选项
AC_CHECK_HEADERS AC_CHECK_HEADERS(head_path1 head_path2…) 检测是否存在头文件
AC_CONFIG_SRCDIR (unique-file-in-source-dir) 检测源码是否存在,保证项目目录是正确的目录
AC_CONFIG_AUXDIR 指定辅助脚本文件目录
AC_CONFIG_HEADERS ([config.h]) 用于实例化config.h头文件
AC_CONFIG_FILES (filename) 指定输出的文件,如AC_CONFIG_FILE(Makefile),他会根据Makefile.in生成Makefile文件
AC_PROG_CC 自动检测gcc
AC_PROG_LIBTOOLS 自动检测libtools
AC_CHECK_FUNCS AC_CHECK_FUNCS([func1 func2 func3]) 检测对应函数是否可用
AC_SEARCH_LIBS AC_SEARCH_LIBS (function, search-libs, [action-if-found], [action-if-not-found], [other-libraries]) 在search-libs中检测function是否存在
AC_OUTPUT 用于创建configure.status,他用来创建Makefile, 一般在最后一行 AS_IF AS_IF (test1, [run-if-true1], …, [run-if-false]) 执行检测,如果成功执行第一条,如果第一条不成功执行第二条,以此类推

例如:


AC_PREREQ(2.61)
AC_INIT(sqlite, 3.38.5, http://www.sqlite.org)
AC_CONFIG_SRCDIR([sqlite3.c]) # 检测当前目录下是否存在sqlite3.c
AC_CONFIG_AUX_DIR([.])

# Use automake.
AM_INIT_AUTOMAKE([foreign])

AC_SYS_LARGEFILE

# Check for required programs.
AC_PROG_CC
AC_PROG_LIBTOOL
AC_PROG_MKDIR_P

# Check for library functions that SQLite can optionally use.
AC_CHECK_FUNCS([fdatasync usleep fullfsync localtime_r gmtime_r])
AC_FUNC_STRERROR_R

AC_CONFIG_FILES([Makefile sqlite3.pc])
BUILD_CFLAGS=
AC_SUBST(BUILD_CFLAGS)

AC_OUTPUT

Makefile.am

  1. PLV
    目标列表变量,用于指定目标文件,定义为: prefix_PRIMARY = product1 product2 ...
    常见前缀有:

    | 名称 | 说明|
    |-|-|
    | bin | 可执行程序安装位置,默认为 /usr/local/bin |
    | lib | 库文件安装位置,默认为 /usr/local/lib |
    | noinst | 生成但不安装,常用于静态库 |
    | check | 测试构建的目标,无需安装 |

    主变量有:

    |名称 | 说明 |
    |-|-|
    | PROGRAMS | 执行程序 |
    | LIBRARIES | 静态库 |
    | LTLIBRARIES | libtool生成的库(.la)|

  2. PSV
    目标源文件变量,指定目标文件的源文件列表,格式如下product_SOURCES = file1 file2 ...
  3. POV
    目标选项变量,常用的选项有:

    | 名称 | 说明 |
    |-|-|
    | product_CPPFLAGS | 预处理器参数 |
    | product_LDFLAGS | 链接参数,如-static -shared -L等 |
    | library_LIBADD | 将非Libtool的.o目标文件传给ar命令,生成静态库 |
    | product_CFLAGS | 编译器参数,如-g -Wall -I等 |
    | program_LDADD | 将静态库或.la传给链接器,用于链接生成可执行程序 |
    | library_LIBADD | 将LibTool的.lo文件添加到LibTool库文件 |

AUTOMAKE_OPTIONS = foreign // 检查等级
bin_PROGRAMS = hello // 生成的可执行程序
hello_sources = hello.c // hello需要的源文件
hello_LDADD = libcn.a // 补充的静态库
noinst_LIBRARIES = libcn.a // 生成静态库
libcn_a_SOURCES = cn.c // libcn.a需要的源文件

目标源文件变量中的product只支持字母,数字和下划线,因此他会将所有其他字符识别为下划线,因此libcn.a变成了libcn_a

实例

本例子为sqlite的源文件

configure.ac


#-----------------------------------------------------------------------
# Supports the following non-standard switches.
#
# --enable-threadsafe
# --enable-readline
# --enable-editline
# --enable-static-shell
# --enable-dynamic-extensions
#

AC_PREREQ(2.61)
AC_INIT(sqlite, 3.38.5, http://www.sqlite.org) # 名称,版本,网站,邮箱等信息
AC_CONFIG_SRCDIR([sqlite3.c]) # 检测当前目录下是否存在sqlite3.c
AC_CONFIG_AUX_DIR([.]) # 指定辅助文件存放目录

# Use automake.
AM_INIT_AUTOMAKE([foreign]) # 确定automake检查级别

AC_SYS_LARGEFILE # 可以使用大文件的宏

# Check for required programs.
AC_PROG_CC # 自动检测要使用的gcc
AC_PROG_LIBTOOL
AC_PROG_MKDIR_P

# Check for library functions that SQLite can optionally use.
AC_CHECK_FUNCS([fdatasync usleep fullfsync localtime_r gmtime_r])
AC_FUNC_STRERROR_R # 检测strerror_r函数

AC_CONFIG_FILES([Makefile sqlite3.pc]) # 指定输出文件
BUILD_CFLAGS=
AC_SUBST(BUILD_CFLAGS) # 输出能被Makefile.am使用的变量

#-------------------------------------------------------------------------
# Two options to enable readline compatible libraries:
#
# --enable-editline
# --enable-readline
#
# Both are enabled by default. If, after command line processing both are
# still enabled, the script searches for editline first and automatically
# disables readline if it is found. So, to use readline explicitly, the
# user must pass "--disable-editline". To disable command line editing
# support altogether, "--disable-editline --disable-readline".
#
# When searching for either library, check for headers before libraries
# as some distros supply packages that contain libraries but not header
# files, which come as a separate development package.
#
AC_ARG_ENABLE(editline, [AS_HELP_STRING([--enable-editline],[use BSD libedit])]) # 添加editline选项
AC_ARG_ENABLE(readline, [AS_HELP_STRING([--enable-readline],[use readline])])

AS_IF([ test x"$enable_editline" != xno ],[ # 如果有editline选项
AC_CHECK_HEADERS([editline/readline.h],[ # 检测是否存在readline头文件
sLIBS=$LIBS
LIBS=""
AC_SEARCH_LIBS([readline],[edit],[ # 检测edit库中是否存在readline
AC_DEFINE([HAVE_EDITLINE],1,Define to use BSD editline) # 失败操作
READLINE_LIBS="$LIBS -ltinfo"
enable_readline=no
],[],[-ltinfo])
AS_UNSET(ac_cv_search_readline)
LIBS=$sLIBS
])
])

AS_IF([ test x"$enable_readline" != xno ],[
AC_CHECK_HEADERS([readline/readline.h],[
sLIBS=$LIBS
LIBS=""
AC_SEARCH_LIBS(tgetent, termcap curses ncurses ncursesw, [], [])
AC_SEARCH_LIBS(readline,[readline edit], [
AC_DEFINE([HAVE_READLINE],1,Define to use readline or wrapper)
READLINE_LIBS=$LIBS
])
LIBS=$sLIBS
])
])

AC_SUBST(READLINE_LIBS)
#-----------------------------------------------------------------------

#-----------------------------------------------------------------------
# --enable-threadsafe
#
AC_ARG_ENABLE(threadsafe, [AS_HELP_STRING(
[--enable-threadsafe], [build a thread-safe library [default=yes]])],
[], [enable_threadsafe=yes])
if test x"$enable_threadsafe" == "xno"; then
BUILD_CFLAGS="$BUILD_CFLAGS -DSQLITE_THREADSAFE=0"
else
BUILD_CFLAGS="$BUILD_CFLAGS -D_REENTRANT=1 -DSQLITE_THREADSAFE=1"
AC_SEARCH_LIBS(pthread_create, pthread)
AC_SEARCH_LIBS(pthread_mutexattr_init, pthread)
fi
#-----------------------------------------------------------------------

#-----------------------------------------------------------------------
# --enable-dynamic-extensions
#
AC_ARG_ENABLE(dynamic-extensions, [AS_HELP_STRING(
[--enable-dynamic-extensions], [support loadable extensions [default=yes]])],
[], [enable_dynamic_extensions=yes])
if test x"$enable_dynamic_extensions" != "xno"; then
AC_SEARCH_LIBS(dlopen, dl)
else
BUILD_CFLAGS="$BUILD_CFLAGS -DSQLITE_OMIT_LOAD_EXTENSION=1"
fi
AC_MSG_CHECKING([for whether to support dynamic extensions])
AC_MSG_RESULT($enable_dynamic_extensions)
#-----------------------------------------------------------------------

#-----------------------------------------------------------------------
# --enable-math
#
AC_ARG_ENABLE(math, [AS_HELP_STRING(
[--enable-math], [SQL math functions [default=yes]])],
[], [enable_math=yes])
AC_MSG_CHECKING([SQL math functions])
if test x"$enable_math" = "xyes"; then
BUILD_CFLAGS="$BUILD_CFLAGS -DSQLITE_ENABLE_MATH_FUNCTIONS"
AC_MSG_RESULT([enabled])
AC_SEARCH_LIBS(ceil, m)
else
AC_MSG_RESULT([disabled])
fi
#-----------------------------------------------------------------------

#-----------------------------------------------------------------------
# --enable-fts4
#
AC_ARG_ENABLE(fts4, [AS_HELP_STRING(
[--enable-fts4], [include fts4 support [default=yes]])],
[], [enable_fts4=yes])
AC_MSG_CHECKING([FTS4 extension])
if test x"$enable_fts4" = "xyes"; then
BUILD_CFLAGS="$BUILD_CFLAGS -DSQLITE_ENABLE_FTS4"
AC_MSG_RESULT([enabled])
else
AC_MSG_RESULT([disabled])
fi
#-----------------------------------------------------------------------

#-----------------------------------------------------------------------
# --enable-fts3
#
AC_ARG_ENABLE(fts3, [AS_HELP_STRING(
[--enable-fts3], [include fts3 support [default=no]])],
[], [])
AC_MSG_CHECKING([FTS3 extension])
if test x"$enable_fts3" = "xyes" -a x"$enable_fts4" = "xno"; then
BUILD_CFLAGS="$BUILD_CFLAGS -DSQLITE_ENABLE_FTS3"
AC_MSG_RESULT([enabled])
else
AC_MSG_RESULT([disabled])
fi
#-----------------------------------------------------------------------

#-----------------------------------------------------------------------
# --enable-fts5
#
AC_ARG_ENABLE(fts5, [AS_HELP_STRING(
[--enable-fts5], [include fts5 support [default=yes]])],
[], [enable_fts5=yes])
AC_MSG_CHECKING([FTS5 extension])
if test x"$enable_fts5" = "xyes"; then
AC_MSG_RESULT([enabled])
AC_SEARCH_LIBS(log, m)
BUILD_CFLAGS="$BUILD_CFLAGS -DSQLITE_ENABLE_FTS5"
else
AC_MSG_RESULT([disabled])
fi
#-----------------------------------------------------------------------

#-----------------------------------------------------------------------
# --enable-rtree
#
AC_ARG_ENABLE(rtree, [AS_HELP_STRING(
[--enable-rtree], [include rtree support [default=yes]])],
[], [enable_rtree=yes])
AC_MSG_CHECKING([RTREE extension])
if test x"$enable_rtree" = "xyes"; then
BUILD_CFLAGS="$BUILD_CFLAGS -DSQLITE_ENABLE_RTREE -DSQLITE_ENABLE_GEOPOLY"
AC_MSG_RESULT([enabled])
else
AC_MSG_RESULT([disabled])
fi
#-----------------------------------------------------------------------

#-----------------------------------------------------------------------
# --enable-session
#
AC_ARG_ENABLE(session, [AS_HELP_STRING(
[--enable-session], [enable the session extension [default=no]])],
[], [])
AC_MSG_CHECKING([Session extension])
if test x"$enable_session" = "xyes"; then
BUILD_CFLAGS="$BUILD_CFLAGS -DSQLITE_ENABLE_SESSION -DSQLITE_ENABLE_PREUPDATE_HOOK"
AC_MSG_RESULT([enabled])
else
AC_MSG_RESULT([disabled])
fi
#-----------------------------------------------------------------------

#-----------------------------------------------------------------------
# --enable-debug
#
AC_ARG_ENABLE(debug, [AS_HELP_STRING(
[--enable-debug], [build with debugging features enabled [default=no]])],
[], [])
AC_MSG_CHECKING([Build type])
if test x"$enable_debug" = "xyes"; then
BUILD_CFLAGS="$BUILD_CFLAGS -DSQLITE_DEBUG -DSQLITE_ENABLE_SELECTTRACE -DSQLITE_ENABLE_WHERETRACE"
CFLAGS="-g -O0"
AC_MSG_RESULT([debug])
else
AC_MSG_RESULT([release])
fi
#-----------------------------------------------------------------------

#-----------------------------------------------------------------------
# --enable-static-shell
#
AC_ARG_ENABLE(static-shell, [AS_HELP_STRING(
[--enable-static-shell],
[statically link libsqlite3 into shell tool [default=yes]])],
[], [enable_static_shell=yes])
if test x"$enable_static_shell" = "xyes"; then
EXTRA_SHELL_OBJ=sqlite3-sqlite3.$OBJEXT
else
EXTRA_SHELL_OBJ=libsqlite3.la
fi
AC_SUBST(EXTRA_SHELL_OBJ)
#-----------------------------------------------------------------------

AC_CHECK_FUNCS(posix_fallocate)
AC_CHECK_HEADERS(zlib.h,[
AC_SEARCH_LIBS(deflate,z,[BUILD_CFLAGS="$BUILD_CFLAGS -DSQLITE_HAVE_ZLIB"])
])

AC_SEARCH_LIBS(system,,,[SHELL_CFLAGS="-DSQLITE_NOHAVE_SYSTEM"])
AC_SUBST(SHELL_CFLAGS)

#-----------------------------------------------------------------------
# UPDATE: Maybe it's better if users just set CFLAGS before invoking
# configure. This option doesn't really add much...
#
# --enable-tempstore
#
# AC_ARG_ENABLE(tempstore, [AS_HELP_STRING(
# [--enable-tempstore],
# [in-memory temporary tables (never, no, yes, always) [default=no]])],
# [], [enable_tempstore=no])
# AC_MSG_CHECKING([for whether or not to store temp tables in-memory])
# case "$enable_tempstore" in
# never ) TEMP_STORE=0 ;;
# no ) TEMP_STORE=1 ;;
# always ) TEMP_STORE=3 ;;
# yes ) TEMP_STORE=3 ;;
# * )
# TEMP_STORE=1
# enable_tempstore=yes
# ;;
# esac
# AC_MSG_RESULT($enable_tempstore)
# AC_SUBST(TEMP_STORE)
#-----------------------------------------------------------------------

AC_OUTPUT

Makefile.am


AM_CFLAGS = @BUILD_CFLAGS@ // @...@是特殊的语法,它引用configure.ac中定义的变量
lib_LTLIBRARIES = libsqlite3.la
libsqlite3_la_SOURCES = sqlite3.c
libsqlite3_la_LDFLAGS = -no-undefined -version-info 8:6:8

bin_PROGRAMS = sqlite3
sqlite3_SOURCES = shell.c sqlite3.h
EXTRA_sqlite3_SOURCES = sqlite3.c
sqlite3_LDADD = @EXTRA_SHELL_OBJ@ @READLINE_LIBS@
sqlite3_DEPENDENCIES = @EXTRA_SHELL_OBJ@
sqlite3_CFLAGS = $(AM_CFLAGS) -DSQLITE_ENABLE_EXPLAIN_COMMENTS -DSQLITE_ENABLE_DBPAGE_VTAB -DSQLITE_ENABLE_STMTVTAB -DSQLITE_ENABLE_DBSTAT_VTAB $(SHELL_CFLAGS)

include_HEADERS = sqlite3.h sqlite3ext.h

EXTRA_DIST = sqlite3.1 tea Makefile.msc sqlite3.rc sqlite3rc.h README.txt Replace.cs Makefile.fallback
pkgconfigdir = ${libdir}/pkgconfig
pkgconfig_DATA = sqlite3.pc

man_MANS = sqlite3.1