autoconf AC_ARG_WITH, AC_CACHE_CHECK, AC_TRY_LINK宏学习

来源:互联网 发布:seo公司usseo 编辑:程序博客网 时间:2024/06/14 08:26
http://www.searchtb.com/2011/07/autoconf-ac_arg_with-ac_cache_check-ac_try_link.html


最近在在RHEL4上编译一个使用Hadoop pipes库的程序浪费了很多时间。这个程序之前使用Hadoop 0.19.1 pipes库,现在Hadoop pipes版本提高到0.20.2,所以要修改configure.ac。但是改过configure.ac文件之后,程序在RHEL4上却又编译不过。为了让程序在RHEL4和RHEL5都能编译通过,则必须让程序编译时链接正确的库,RHEL4链接0.19.1版本,RHEL5链接0.20.2版本。从唐逸那里求得一本超赞的autoconf指南,啃了两天,略有小成,于是决定找个开源项目的configure.ac文件研究一番。发现memcached的比较简单,并且它还依赖libevent,就研究它了。

AC_ARG_WITH, AC_CACHE_CHECK, AC_TRY_LINK是autoconf中非常有用的三个宏,configure.ac文件中一大部分就是在用这三个宏。这三个宏的定义如下所示。

AC_ARG_WITH (package, help-string, [action-if-given], [action-if-not-given])

AC_CACHE_CHECK (message, cache-id, commands-to-set-it)

AC_TRY_LINK (includes, function-body, [action-if-true], [action-if-false])

memcached configure.in检测libevent的代码如下:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
trylibeventdir=""
AC_ARG_WITH(libevent,
       [  --with-libevent=PATH     Specify path to libevent installation ],
       [
                if test "x$withval" != "xno" ; then
                        trylibeventdir=$withval
                fi
       ]
)
 
dnl ------------------------------------------------------
dnl libevent detection.  swiped from Tor.  modified a bit.
 
LIBEVENT_URL=http://www.monkey.org/~provos/libevent/
 
AC_CACHE_CHECK([for libevent directory], ac_cv_libevent_dir, [
  saved_LIBS="$LIBS"
  saved_LDFLAGS="$LDFLAGS"
  saved_CPPFLAGS="$CPPFLAGS"
  le_found=no
  for ledir in $trylibeventdir "" $prefix /usr/local ; do
    LDFLAGS="$saved_LDFLAGS"
    LIBS="$saved_LIBS -levent"
 
    # Skip the directory if it isn't there.
    if test ! -z "$ledir" -a ! -d "$ledir" ; then
       continue;
    fi
    if test ! -z "$ledir" ; then
      if test -d "$ledir/lib" ; then
        LDFLAGS="-L$ledir/lib $LDFLAGS"
      else
        LDFLAGS="-L$ledir $LDFLAGS"
      fi
      if test -d "$ledir/include" ; then
        CPPFLAGS="-I$ledir/include $CPPFLAGS"
      else
        CPPFLAGS="-I$ledir $CPPFLAGS"
      fi
    fi
    # Can I compile and link it?
    AC_TRY_LINK([#include <sys/time.h>
#include <sys/types.h>
#include <event.h>], [ event_init(); ],
       [ libevent_linked=yes ], [ libevent_linked=no ])
    if test $libevent_linked = yes; then
       if test ! -z "$ledir" ; then
         ac_cv_libevent_dir=$ledir
       else
         ac_cv_libevent_dir="(system)"
       fi
       le_found=yes
       break
    fi
  done
  LIBS="$saved_LIBS"
  LDFLAGS="$saved_LDFLAGS"
  CPPFLAGS="$saved_CPPFLAGS"
  if test $le_found = no ; then
    AC_MSG_ERROR([libevent is required.  You can get it from $LIBEVENT_URL
 
      If it's already installed, specify its path using --with-libevent=/dir/
])
  fi
])
LIBS="$LIBS -levent"
if test $ac_cv_libevent_dir != "(system)"; then
  if test -d "$ac_cv_libevent_dir/lib" ; then
    LDFLAGS="-L$ac_cv_libevent_dir/lib $LDFLAGS"
    le_libdir="$ac_cv_libevent_dir/lib"
  else
    LDFLAGS="-L$ac_cv_libevent_dir $LDFLAGS"
    le_libdir="$ac_cv_libevent_dir"
  fi
  if test -d "$ac_cv_libevent_dir/include" ; then
    CPPFLAGS="-I$ac_cv_libevent_dir/include $CPPFLAGS"
  else
    CPPFLAGS="-I$ac_cv_libevent_dir $CPPFLAGS"
  fi
fi

1-9行是在判断用户是否指定libevent的目录,如果没有指定的话,trylibeventdir将会是一个空值。这里并没有使用AC_HELP_STRING,所以”–with-libevent”前面有两个空格,要不然”congfigure –help”输出的格式不会太美观。

16-40行在遍历用户指定libevent的目录,以及prefix和/usr/local这几个目录(注意检查的先后顺序),如果存在一个合适的目录,那么就设置$LIBS, $LDFLAGS和$CPPFLAGS。这几个环境变量是为后面执行AC_TRY_LINK做准备的。它会遍历这三个目录是否安装libevent库,只要有一个目录下有libevent库就行,所以如果系统安装了,即使用户指定错了也没有关系。这里有一个空字符串,我怀疑是个bug,应该指定为当前目录才对。

42-54行在检查libevent库是否可用。如果仅仅检测到libevent.so存在并不能保证该库一定可用,最有效的方法是执行一个小程序测试下。这里调用了ev_init函数检查libevent库是否可用。如果检测到libevent库是可用的,那么将ac_cv_libevent_dir写入到cache中。关于cache的使用,后面会有详细的说明。

56-64行恢复$LIBS, $LDFLAGS和$CPPFLAGS这三个变量,如果最终没有找到可用的libevent库,那么AC_MSG_ERROR打印一个错误信息并退出。

66-80行在设置LIBS,这个变量将用在Makefile中。如果用的是系统的libevent,因为/usr/local/lib已经是默认的库加载目录,所以不许要特别指定。否则的话要设置LDFLAGS和CPPFLAGS两个变量值。

默认情况下configure不会使用cache,当指定-C参数时,configure会生成一个config.cache文件。AC_CACHE_CHECK首先会去该文件中查找变量的值,如果找到了,最后那个宏是不会被执行的。缓存的内容如下所示。

ac_cv_libevent_dir=${ac_cv_libevent_dir='(system)'}

configure执行时,如果发现该变量是从cache中读取时,会打印出以下信息。

checking for libevent directory... (cached) (system)

可以看出这段代码中cache拥有最高的级别,如果前面运行configure时指定错了cache,后面configure就不能正确执行了。这时可以使用”make distclean”删除cache文件。

如果要在RHEL4的机器上链接hadoop 0.19.1 pipes库,而在RHEL5的机器上链接0.20.2 pipes库,只需要将二者的路径都放到try的路径中。在RHEL4上链接0.19.1 pipes库时AC_TRY_LINK会成功,在RHEL5上则是链接0.20.2 pipes库才会成功,这样就能在所有的机器上都链接上正确的库。

感觉autoconf非常之复杂,有许多宏要学习。要彻底搞明白autoconf还需要学习libtools和Makefile,真是路漫漫其修远兮,上下求索而不得啊~


0 0
原创粉丝点击