17

I need to conditionally compile some code based on the presence of a library. Seems like this should be easy with autoconf/automake but I can't figure it out.

For example, if there is a PNG library present, I want to include code to use it. My configure.ac has:

AC_CHECK_LIB([png], [png_create_write_struct_2])

and my Makefile.am has:

if USE_LIBPNG
libdev_la_SOURCES += png.c
endif

(which adds png.c to the list of sources for libdev so it gets compiled).

An automake conditional like USE_LIBPNG requires the conditional be defined in configure.ac, so i need:

AM_CONDITIONAL([USE_LIBPNG], [test SOMETHINGOROTHER])

The question is, what can test SOMETHINGOROTHER be? What does AC_CHECK_LIB define that I can test for?

AC_CHECK_LIB's default behavior is to define a symbol (in config.h) which can be used in source code, but that doesn't help the Makefile since the AM_CONDITIONAL needs a shell test

I tried overriding the default AC_CHECK_LIB behavior like so:

AC_CHECK_LIB([png], [png_create_write_struct_2], [HAS_LIBPNG=1])

after which I could test for it:

AM_CONDITIONAL([USE_LIBPNG], [test "x$HAS_LIBPNG" = "x1"])

This is ugly, but works for the Makefile... but creates a new problem: since it discards the original AC_CHECK_LIB behavior, and I no longer get a symbol added to config.h, which I need.

I must be missing something basic, or possible Doing It Wrong. Have been digging around for hours and found no answer.

Anyone?

Ian Macky
  • 197
  • 1
  • 1
  • 6
  • The [autoconf manual gives some examples](https://www.gnu.org/software/autoconf/manual/autoconf-2.60/html_node/External-Software.html) – Phil Frost Apr 04 '20 at 23:33

3 Answers3

31

If the library you're checking for supplies a .pc file for use with pkg-config, then you're much better off using PKG_CHECK_MODULES to get the correct flags. libpng does:

(in configure.ac)

PKG_CHECK_MODULES([libpng], [libpng12])

This gives you access to the variables $(libpng_CFLAGS) and $(libpng_LIBS) which you will want to add to Makefile.am (probably in AM_CFLAGS/AM_CXXFLAGS and LDADD, or target-specific versions thereof).

It will also cause configure to fail with an error if libpng12.pc isn't found. If you want configure to continue, you'll need to supply the third and fourth arguments to PKG_CHECK_MODULES, which are ACTION-IF-FOUND and ACTION-IF-NOT-FOUND:

(in configure.ac)

PKG_CHECK_MODULES([libpng], [libpng12], [HAVE_LIBPNG=1], [HAVE_LIBPNG=0])

Now, if you need an automake conditional, you can do something like:

(in configure.ac)

AM_CONDITIONAL([USE_LIBPNG], [test "$HAVE_LIBPNG" -eq 1])

If you also need the preprocessor definition, you could use AC_DEFINE like so:

(in configure.ac)

AS_IF([test "$USE_LIBPNG" -eq 1], [AC_DEFINE([USE_LIBPNG], [1], [Define if using libpng.])])

Possibly nicer is to set the definition in Makefile.am:

(in Makefile.am)

AM_CPPFLAGS =
if USE_LIBPNG
AM_CPPFLAGS += -DUSE_LIBPNG
endif

This will clutter your command line, though, whereas AC_DEFINE can put the definition in a header if you use AC_CONFIG_HEADERS. I guess this doesn't really matter if you use AM_SILENT_RULES([yes]) or don't care about your command line being neat (and let's be honest, automake generates some pretty gnarly command lines anyway).

A note on good autoconf style

It is considered poor form to build optional support based on whether or not a check succeeded (see this gentoo doc for details). Here's how I'd code optional support for libpng:

(in configure.ac)

# This is because the first PKG_CHECK_MODULES call is inside a conditional.
PKG_PROG_PKG_CONFIG

AC_ARG_WITH([libpng],
  [AS_HELP_STRING([--with-libpng],
    [support handling png files @<:@default=check@:>@])],
  [],
  [with_libpng=check])
AS_CASE(["$with_libpng"],
  [yes], [PKG_CHECK_MODULES([libpng], [libpng12], [HAVE_LIBPNG=1])],
  [no], [],
  [PKG_CHECK_MODULES([libpng], [libpng12], [HAVE_LIBPNG=1], [HAVE_LIBPNG=0])])
AM_CONDITIONAL([USE_LIBPNG], [test "$with_libpng" != no -a "$HAVE_LIBPNG" -eq 1])

(in Makefile.am)

if USE_LIBPNG
AM_CPPFLAGS += -DUSE_LIBPNG
AM_CFLAGS += $(libpng_CFLAGS)
LDADD += $(libpng_LIBS)
libdev_la_SOURCES += png.c
endif

If your library doesn't have a .pc file

For completeness, here's how I'd check for a library that didn't have a .pc file. I'll skip over the details of following good autoconf style. AC_CHECK_LIB sets a cache variable, so you can test that instead of replacing the ACTION-IF-FOUND of AC_CHECK_LIB:

(in configure.ac)

AC_CHECK_LIB([png], [png_create_write_struct_2])

# Then test:
AS_IF([test "$ac_cv_lib_png_png_create_write_struct_2" = yes], [HAVE_LIBPNG=1], [HAVE_LIBPNG=0])

# Or set conditional:
AM_CONDITIONAL([USE_LIBPNG], [test "$ac_cv_lib_png_png_create_write_struct_2" = yes])

IMHO, you should only do it this way if you have no other option.

Jeremy Kerr
  • 1,895
  • 12
  • 24
Jack Kelly
  • 18,264
  • 2
  • 56
  • 81
  • Excellent, comprehensive answer! – ptomato Mar 03 '11 at 10:42
  • @William, are you going to offer an explanation? – Jack Kelly Mar 03 '11 at 19:33
  • 1
    @Jack Using PKG_CHECK_MODULES forces the user to either have pkg-config installed on the box, or to set PKG_CONFIG=true and set LDFLAGS, etc. by hand as if AC_CHECK_LIB had been used instead of PKG_CHECK_MODULES. But, since the configury relied on PKG_CHECK_MODULES to determine the existence of the library, and the user had to override pkg-config, there is no actual check if the library is available. Most major platforms will work with PKG_CHECK_MODULES, but the edge cases are what autoconf is good for...and PKG_CHECK_MODULES doesn't work there...somewhat defeating the purpose. – William Pursell Mar 03 '11 at 19:44
  • @William: You don't need to override `PKG_CONFIG` to override the flags for a package. You can tell which packages are required by looking at `./configure --help`, so I don't see this as a major issue. What platforms have you used that don't support `pkg-config`? I know windows doesn't come with it, but you can install it quite easily (and if you're running configure scripts on windows, you're going to be installing quite a bit by hand, anyway). – Jack Kelly Mar 03 '11 at 19:54
  • 1
    @Jack I only suggest overriding PKG_CONFIG as a way to avoid having to install it. Personally, I have not had any problems using PKG_CHECK_MODULES, but I've stopped using it based on conversations on the autoconf mailing list in which many people do report running into problems. – William Pursell Mar 04 '11 at 14:18
  • 1
    @William: From a quick reading of `pkg.m4`, it does not appear to be fatal if `configure` does not find `pkg-config`, so long as the `FOO_CFLAGS` and `FOO_LIBS` for each dependent package have been set on the `configure` command line. – Jack Kelly Mar 04 '11 at 19:37
1

I will disagree mildly with Jack on his recommendation to use PKG_CHECK_MODULES. It is probably best to avoid using that. But I will agree with Jack on avoiding assigning to LIBS in the 3rd argument to AC_CHECK_LIB. Life is easier if you let AC_CHECK_LIB use the default settings.

Although AC_CHECK_LIB does not define a shell variable indicating whether or not the library was found, you can do this in configure.ac:

AM_CONDITIONAL([USE_LIBPNG],[grep HAVE_LIBPNG confdefs.h > /dev/null])

Arguably, this is relying on internal autoconf details, but in practice will work reliably.

William Pursell
  • 204,365
  • 48
  • 270
  • 300
  • `AC_CHECK_LIB` sets a cache variable, so you could test against that: http://www.gnu.org/software/hello/manual/autoconf/Libraries.html – Jack Kelly Mar 03 '11 at 19:33
1

Thanks for the replies.

Jack: I'm trying for maximum portability, so can't assume the libraries were installed as part of a package (they're not on my own box!), which means the no-other-option solution you suggested is what I already tried-- setting a shell variable manually-- but also manually performs the extra steps that would have been done by AC_CHECK_LIB: prepending the library to LIBS and defining HAVE_LIBxxx.

There was a catch though: autoheader complains about the bare AC_DEFINE:

autoheader: warning: missing template: HAVE_LIBPNG
autoheader: Use AC_DEFINE([HAVE_LIBPNG], [], [Description])

I'd be nice if autoheader worked in the future, so I had to change AC_DEFINE to the full monty:

AC_CHECK_LIB([png], [png_create_write_struct_2],
    [HAS_LIBPNG=1
     LIBS="-lpng $LIBS"
     AC_DEFINE([HAVE_LIBPNG], 1, [Define to 1 if you have the `png' library (-lpng)])])

This works, but I don't much like having to duplicate the default behavior of AC_CHECK_LIB.

William: Yes I could grep for the symbol definition in confdefs.h, that also works.

Both solutions have their pros and cons (what doesn't?). Not sure which way I'll go, but it's nice to have options.

Thanks again.

Ian Macky
  • 197
  • 1
  • 1
  • 6
  • 1
    This feels more like it should be a comment, so I'm going to upvote it to get you closer to the required rep (to leave comments). – Jack Kelly Mar 03 '11 at 19:35
  • 1
    Oh, and also: `pkg-config` supports using not-yet-installed libraries, and and libraries not installed in a system directory. Just set `PKG_CONFIG_PATH`. – Jack Kelly Mar 03 '11 at 22:46
  • 1
    For reference, you can always comment on your own posts and on answers to your own questions, even with 1 rep. – Sam Hanes Dec 02 '12 at 19:48