autoconf
[Top][All Lists]
Advanced

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

Re: How to write a conditional test in configure.ac


From: Eric Blake
Subject: Re: How to write a conditional test in configure.ac
Date: Thu, 12 Jan 2012 16:32:15 -0700
User-agent: Mozilla/5.0 (X11; Linux x86_64; rv:9.0) Gecko/20111222 Thunderbird/9.0

On 01/12/2012 03:58 PM, Svante Signell wrote:
> Hello.
> 
> Consider the code snippet below. How to modify it to get the GNU version
> of baseline if defined (in my case GNU/Hurd). The macro 
> AC_USE_SYSTEM_EXTENSIONS is stated earlier in configure.ac.

First, I'd suggest that you _don't_ use basename(); it has severe
portability problems (POSIX allows, but does not require, it to modify
its incoming argument; worse, POSIX states that these functions need not
be thread-safe, rendering them useless in multithreaded programs) - mere
existence of the function in libgen.h does not tell you whether you will
be encountering those subtle differences as you port to other platforms.
 Besides, on glibc, there are two flavors of basename(), and which
version you get depends on your compile-time options - I guess this is a
case where you were probing for the GNU behavior rather than the POSIX
behavior.  Your test program didn't test for those particular
subtleties.  The gnulib module dirname provides functions dir_name,
base_name, and last_component, which have saner semantics that are
uniform to all platforms and not dependent on POSIX vagaries.

But, if I can't convince you to use gnulib and either base_name() or
last_component(), I can still advise you on how to better use autoconf.

> 
>>From configure.ac:
> # COMPAT_FUNC_BASENAME
> # --------------------
> # Check for working basename() function.
> AC_CHECK_HEADERS([libgen.h])

This is an unconditional check; did you mean for it to be inside the
body of your COMPAT_FUNC_BASENAME?

> AC_DEFUN([COMPAT_FUNC_BASENAME], [
>   AC_DEFINE([NEED_BASENAME], 1,
>             [Define if you want to use the basename function])

This unconditionally defines NEED_BASENAME.  You should instead defer
this line of code until after you have done the cache check.

>   AC_CHECK_HEADERS([libgen.h])

I'd suggest using AC_CHECK_HEADERS_ONCE, as it is more efficient.

>   AC_CACHE_CHECK([for working basename],
>     [compat_cv_func_basename_works],
> 
>     [AC_TRY_RUN([

AC_TRY_RUN is deprecated; also, instead of open-coding your program, I'd
use AC_LANG_PROGRAM.

> #include <stdio.h>
> #include <stdlib.h>
> #ifdef HAVE_LIBGEN_H
> # include <libgen.h>

For this particular test, there's no need to probe for HAVE_LIBGEN_H -
since you are probing for a working basename(), it's perfectly find to
ditch all platforms that lack <libgen.h> with a compiler error.

>     if (strcmp(basename(test1), tests[i].result) ||
>         strcmp(test1, tests[i].test))
>       exit(1);
>   }

It is actually more portable to use 'return 1' than 'exit(1)' in
configure checks, as then you don't have to worry about <stdlib.h>
working right.  Also, strcmp() requires the use of <string.h>.

> ],
>       [compat_cv_func_basename_works=yes],
>       [compat_cv_func_basename_works=no],
>       [compat_cv_func_basename_works=no]

Good, you provided a sane default for cross compilation.

>     )]
>   )
>   if test "$compat_cv_func_basename_works" = "yes"; then
>     AC_DEFINE([HAVE_BASENAME], 1,
>               [Define if your system has a working basename])
>   else
>     AC_LIBOBJ([basename])
>   fi

Yes, this looks like the correct conditional.  In other words, you were
already pretty close - reusing your main() method as-is, I would have
written:

AC_DEFUN([COMPAT_FUNC_BASENAME], [
  AC_CHECK_HEADERS([libgen.h])
  AC_CACHE_CHECK([for working basename],
    [compat_cv_func_basename_works],

    [AC_RUN_IFELSE([[
#include <string.h>
#include <libgen.h>

typedef struct {
  char *test;
  char *result;
} test_t;

const test_t tests[] = {
  { "/usr/local/foo", "foo" },
  { "/usr/local/foo/", "foo" },
  { NULL, NULL }
};
]], [[
  char test1[1024];
  int i;

  for (i = 0; tests[i].test; i++) {
    strcpy(test1, tests[i].test);
    if (strcmp(basename(test1), tests[i].result) ||
        strcmp(test1, tests[i].test))
      return 1;
  }
]],
      [compat_cv_func_basename_works=yes],
      [compat_cv_func_basename_works=no],
      [compat_cv_func_basename_works=no]
    )]
  )
  if test "$compat_cv_func_basename_works" = "yes"; then
    AC_DEFINE([HAVE_BASENAME], 1,
              [Define if your system has a working basename])
  else
    AC_LIBOBJ([basename])
  fi
])

-- 
Eric Blake   address@hidden    +1-919-301-3266
Libvirt virtualization library http://libvirt.org

Attachment: signature.asc
Description: OpenPGP digital signature


reply via email to

[Prev in Thread] Current Thread [Next in Thread]