【转】GNU autotools(四)编写configure.ac

1. 常用的autoconf宏

1.1 AC_PREREQ()

AC_PREREQ宏指定autoconf的最低版本。例子如下:

AC_PREREQ(2.69)

1.2 AC_INIT()

AC_INIT宏初始化autoconf系统。

AC_INIT最多接受五个参数:package名称,version,和可选的bug-report地址,tarname和url。如下的例子指定了前三个。

AC_INIT([helloauto], [1.0], [helloauto-bugs@example.org])

package名称使用一种标准化的形式。automake生成的压缩包被默认命名为tarname-version.tar.gz,tarname被设置为标准化的软件包名(小写,所有标点被转化为下划线)。

bug-report参数,通常设置为一个E-Mail地址,但是任何文本字符串都是有效的。

version参数,最为广泛使用的惯例是传递marjor.minor。但用marjor.minor.reversion也没有错误。如果你喜欢,你甚至可以添加非数字文本到这个宏,例如0.15.alpha。

autoconf从AC_INIT的参数,生成一些替换变量,如:
@PACKAGE_NAME@,
@PACKAGE_VERSION@,
@PACKAGE_TARNAME@,
@PACKAGE_STRING@ ,
@PACKAGE_BUGREPORT@

1.3 AM_INIT_AUTOMAKE

AM_INIT_AUTOMAKEH是auotmake的宏。它初始化automake,参数是调用automake使用的参数(与编译器没有关系)。

例子如下:

AM_INIT_AUTOMAKE([-Wall -Werror foreign])

1.4 PKG_CHECK_MODULES

PKG_CHECK_MODULES是pkg-config工具提供的宏。它检查指定的库是否存在并符合要求。如果是,则设置变量XXX_CFLAGS和XXX_LIBS的值。其中XXX是PKG_CHECK_MODULES宏的第一个参数。

如下的例子,检查libdrm.so是否存在并且版本不低于2.4。如果是,设置变量video_drm的值为yes,否则设置为no。

PKG_CHECK_MODULES(DRM, [libdrm >= 2.4], video_drm="yes",video_drm="no")

1.5 AC_CONFIG_SRCDIR

AC_CONFIG_SRCDIR宏的目的,是让configure脚本知道,它执行的目录是否真是工程的目录。

configure需要能定位自己,因为工程代码可能是来自一个远程目录。AC_CONFIG_SRCDIR给了一个在正确位置查找的重要提示。

AC_CONFIG_SRCDIR指定的文件,应该尽量选择你的项目独有的文件,这样configure不容易把其它项目的目录当成是自己的。

如下的例子指定src/main.c作为这个文件。

AC_CONFIG_SRCDIR([src/main.c])

1.6 AC_CONFIG_HEADERS

AC_CONFIG_HEADERS宏允许指定一个或多个config.status从模板文件生成的头文件。可以在你的头文件模板里放置多个像这样的声明,每行一个。

如下面的例子指定了头文件config.h。当configure.ac修改时,config.status会基于AC_CONFIG_HEADERS宏重新生成config.h。

AC_CONFIG_HEADERS([config.h])

1.7 AC_CHECK_PROG

AC_CHECK_PROG宏检查指定的程序是否存在。

如下面的例子,如果ranlib存在,则变量RANLIB设置为ranlib,否则设置为:。

AC_CHECK_PROG([RANLIB], [ranlib], [:])

1.8 AC_CHECK_TOOL

AC_CHECK_TOOL宏与AC_CHECK_PROG功能类似,它检查指定的程序是否存在。不同的是,它会先检查--host值作为前缀的命令。

举一个例子。如果如下调用configure:

./configure --build=x86_64-gnu --host=i386-gnu

则AC_CHECK_TOOL宏先检查i386-gnu-ranlib是否存在,如果不存在,才继续检查ranlib是否存在。如果程序存在,将RANLIB变量相应地设置为i386-gnu-ranlib或ranlib。

AC_CHECK_TOOL([RANLIB], [ranlib], [:])

1.9 AC_PROG_CC 与 AC_PROG_CXX

AC_PROG_CC宏决定使用哪个C编译器。如果指定了参数,则按照参数指定的顺序检查编译器是否可用。最后将编译器名称写入变量CC。

如下的例子指定按gcc、cc的顺序进行检查。

AC_PROG_CC([gcc cc])

AC_PROG_CXX宏与AC_PROG_CC功能类似,不同的是,它决定使用哪个C++编译器,编译器名称写入变量CXX。

1.8 AC_PROG_INSTALL

AC_PROG_INTALL宏设置变量INSTALL。如果在当前PATH环境下能找到install程序,则将INSTALL设置为install,否则设置为'install-sh -c'。autoconf包中有install-sh,应该将它复制到工程中。

如下是一个例子。

AC_PROG_INSTALL

1.9 AC_SUBST

对于AC_SUBST宏, automake会在Makefile.in中生成一个输出变量,这样Makefile.am中可以使用这个变量,变量的值是它的当前值。

如下的例子生成变量HBLIBSUFFIX。

AC_SUBST(HBLIBSUFFIX)

Makefile.am可以如下使用HBLIBSUFFIX。

lib_LTLIBRARIES += libharfbuzz@HBLIBSUFFIX@.la

1.10 AC_DEFINE 和 AC_DEFINE_UNQUOTED

AC_DEFINE宏和AC_DEFINE_UNQUOTED宏,定义C预编译符号。

缺省情况下,AC_OUTPUT宏把这些符号输出到变量DEFS中,configure将它们传递给编译器;如果configure.ac中调用了AC_CONFIG_HEADERS宏,AC_OUTPUT把它们保存在头文件中,每个符号对应一个#define行。

如下AC_DEFINE的例子定义符号HAVE_VPRINTF=1。第三个参数是说明。只有调用了AC_CONFIG_HEADERS宏才有意义,它是附加在#define行后的注释。

AC_DEFINE([HAVE_VPRINTF], [1], [Define if vprintf exists.])

AC_DEFINE_UNQUOTED与AC_DEFINE不同的地方在于,它能扩展shell符号,包括$(变量展开), `(命令替换),和\ (换行消除)。

如下的例子,先展开conf变量,然后定义符号ETCFILENAME。

AC_DEFINE_UNQUOTED(ETCFILENAME, "${conf}", [MiniGUI configure file name])

1.11 AC_CHECK_HEADERS

AC_CHECK_HEADERS宏检查指定的系统头文件是否存在。

如下的例子检查系统头文件stdlib.h是否存在。

AC_CHECK_HEADERS([stdlib.h])

1.12 AC_CHECK_LIB

AC_CHECK_LIB宏检查指定库中指定的函数是否存在。如果存在,向输出变量LIBS中,加入-llib。

如下的例子检查pthread库是否存在函数pthread_rwlock_init()。

AC_CHECK_LIB([pthread], [pthread_rwlock_init])

1.13 AC_CHECK_FUNC 与 AC_CHECK_FUNCS

AC_CHECK_FUNC宏检查指定的C函数是否可用。如果可用,则定义ac_cv_func_XXX变量并且设置为yes。

如下的例子检查函数vprintf()是否可用。如果可用,则调用AC_DEFINE宏定义变量HAVE_VPRINTF=1。然后根据检查结果继续处理。如果可用(ac_cv_func_vprintf=yes),则继续检查__doprnt()是否可用。

AC_CHECK_FUNC([vprintf], [AC_DEFINE([HAVE_VPRINTF], [1], [Define if vprintf exists.])])
if test "x$ac_cv_func_vprintf" != xyes; then
    AC_CHECK_FUNC([_doprnt], [AC_DEFINE([HAVE_DOPRNT], [1], [Define if _doprnt exists.])])
fi

AC_CHECK_FUNCS宏检查一组函数(名字用空白符分割)是否可用,对于每个可用的函数,定义变量HAVE_XXX。

如下的例子检查C函数time(), mktime(),和localtime()是否可用。

AC_CHECK_FUNCS(time mktime localtime)

1.14 AC_CHECK_DECL 与 AC_CHECK_DECLS

AC_CHECK_DECL宏检查指定的符号(函数、变量、或常量)是否定义。

如下的例子检查变量_MGRM_PROCESSES是否定义。如果是,则变量minigui_runmode赋值procs。

AC_CHECK_DECL(_MGRM_PROCESSES, minigui_runmode="procs")

AC_CHECK_DECLS宏检查一组符号是否定义。这组符号以逗号分隔。对于每一个符号,如果存在,则定义变量HAVE_DECL_XXX,并赋值为1, 否则赋值为0。其中XXX是符号名。

如下的例子。如果列表中的函数(如malloc)已定义,则定义变量HAVE_DECL_MALLOC=1。

AC_CHECK_DECLS([malloc, realloc, calloc, free])

1.15 AS_HELP_STRING

AS_HELP_STRING宏是用于打印"configure --help"输出中,类似如下的格式化信息。

--with-foo    use foo (default is no)

AS_HELP_STRING有两个参数,对应于信息的左右两边,"--with-foo" 和 "use foo (default is no)"。如下是AS_HELP_STRING对应的例子。

AS_HELP_STRING([--with-foo], [use foo (default is no)])

1.16 AC_ARG_ENABLE

你的软件包可能有些可选的特性。执行configure时,用户可以选择使能或禁用某个特性。

configure --enable-feature=yes

使用AC_ARG_ENABLE宏可以创建一个--enable-XXX选项。四个参数依次是特性名称、提示字符串、用户指定--enable-XXX选项时的动作(yes或no),没指定选项时的动作。

如果用户指定了--enable-XXX选项,则指定的值会保存在变量enableval中。

如下的例子指定了特性debug。如果用户指定了选项,则检查enableval值,如果要求使能选项,则设置变量debug为true,否则设置为false,其他值报告错误;如果没指定选项,设置debug为false。

AC_ARG_ENABLE([debug],
  [--enable-debug Turn on debugging],
  [case "${enableval}" in
     yes) debug = true ;;
     no) debug = false ;;
     *) AC_MSG_ERROR([bad value ${enableval} for --enable-debug]) ;;
   esac], 
  [debug = false])

1.17 AC_ARG_WITH

工程可能依赖第三方软件包,这个包是否存在,会导致你的软件的不同行为。执行configure时,可以允许软件的使用者指定是否使用第三方包。

configure --with-foo=yes

使用AC_ARG_WITH宏可以创建一个--with-XXX选项。宏的四个参数依次是第三方包的名称、提示字符串、用户指定--with-XXX选项时的动作(不管是yes,还是no或其他),没指定选项时的动作。

如果用户指定了--with-XXX选项,则指定的值会保存在变量withval中。

如下的例子指定了包名foo,用户指定选项时,设置use_foo变量为$withval,没指定则设置为no。注意,这里用AS_HELP_STRING宏构造了提供格式化的字符串。

AC_ARG_WITH([foo],
    [AS_HELP_STRING([--with-foo], [use foo (default is no)])],
    [use_foo=$withval],
    [use_foo=no])

1.18 AM_CONDITIONAL

AM_CONDITIONAL宏检查指定的条件,并定义变量和赋值。这个变量是在configure运行时赋值的,比如根据用户给configure指定的参数。

下面的例子定义DEBUG变量,并根据AC_ARG_ENABLE宏定义的变量debug赋值。

AC_ARG_ENABLE([debug],
  [--enable-debug Turn on debugging],
  [case "${enableval}" in
     yes) debug = true ;;
     no) debug = false ;;
     *) AC_MSG_ERROR([bad value ${enableval} for --enable-debug]) ;;
   esac], [debug = false])
AM_CONDITIONAL([DEBUG], [test x$debug = xtrue])

1.19 AC_CONFIG_FILES

AC_CONFIG_FILES宏将模板文件实例化,输出文件。它的参数是用空白符或换行符分割的一组文件名。参数中的文件是输出文件名,它假设模板文件名是输出文件名加后缀.in。

如下面的例子,从模板文件Makefile.in,生成Makefile,从src/Makefile.in生成src/Makefile。这样在Makefile.in修改后,对应的Makefile会相应得到更新。

AC_CONFIG_FILES([Makefile src/Makefile])

1.20 AC_OUTPUT

AC_OUTPUT宏产生config.status,并执行它。config.status负责产生Makefile和其他文件。

AC_OUTPUT

1.21 AC_MSG_CHECKING 与 AC_MSG_RESULT

这两个宏是配对使用的,用于检查某个系统特性。

AC_MSG_CHECKING宏打印出类似"Checking XXX ..."的提示,XXX是是它的参数。AC_MSG_RESULT宏输出检查结果,如yes、no或其他内容。

如下是一个例子:

hb_os_win32=no
AC_MSG_CHECKING([for native Win32])
case "$host" in
  *-*-mingw*)
    hb_os_win32=yes
    ;;  
esac
AC_MSG_RESULT([$hb_os_win32])

它的输出可能是:

Checking for native Win32 ... yes

1.22 AC_MSG_XXX

有一组宏用于打印不同级别的脚本调试信息。

AC_MSG_NOTICE:打印调试信息。
AC_MSG_WARN:打印警告信息,不终止configure运行。
AC_MSG_ERROR:打印错误信息,中止configure运行。
AC_MSG_FAILURE:打印错误信息,写入config.log

如下是AC_MSG_NOTICE宏的例子,它展开enable_doc变量,然后打印字符串。

AC_MSG_NOTICE([build configuration: documentation:${enable_doc}])

2. configure.ac的例子

如下是helloauto工程的布局。其中用[]包括的文件是用autotools生成的文件。configure.ac也可以在autoscan工具生成的configure.scan基础上修改得到。

- helloauto
  ├── src
  │   ├── main.c
  │   ├── Makefile.am
  │   ├── [config.h.in]
  │   └── [config.h]
  ├── configure.ac
  ├── Makefile.am
  └── [configure]

使用的configure.ac如下:

# configure.ac
 
AC_PREREQ([2.69])
AC_INIT([helloauto], [1.0], [helloauto-bugs@example.org])
AC_CONFIG_SRCDIR([src/main.c])
AC_CONFIG_HEADERS([config.h])
 
# Checks for programs.
AC_PROG_CC
AC_PROG_INSTALL
 
# 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([Makefile src/Makefile])

AC_OUTPUT

参考文档

官方文档之autoconf宏索引
configure.ac与Makefile.am宏定义说明
pkg-config使用指南

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 212,185评论 6 493
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 90,445评论 3 385
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 157,684评论 0 348
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 56,564评论 1 284
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 65,681评论 6 386
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 49,874评论 1 290
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 39,025评论 3 408
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 37,761评论 0 268
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 44,217评论 1 303
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 36,545评论 2 327
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 38,694评论 1 341
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 34,351评论 4 332
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 39,988评论 3 315
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 30,778评论 0 21
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 32,007评论 1 266
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 46,427评论 2 360
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 43,580评论 2 349

推荐阅读更多精彩内容