0
votes

I have a library that I am developing the configuration and makefiles for using Autotools suite. The library requires an external library (specifically fftw3) on the system it is being compiled on and I want Autoconf/Automake to automatically find and link/include the external library before/when compiling (Either in configure.ac or Makefile.am).

I currently am just using autoconf "--with-" flags for the user to provide the location of both the library file and the include folder of the external library on their system, but this seems like such a hassle for the user. The library I am building the configure file and makefiles for will be deployed on various shared systems, so it's difficult to assume the necessary external library will always be in the same place.

What's the best way to approach this?

2

2 Answers

2
votes

You may be overthinking this. That libraries may be installed in different places on different systems is not in itself an issue. Development toolchains know about the layouts of the systems on which they are used. The base case is fairly robust; just (for example) ...

AC_CHECK_LIB([fftw3], [fftw_plan_dft])

That will recognize that libfftw3 is available in the search path if indeed it is, and in that case will prepend the appropriate link option to the LIBS variable and define HAVE_LIBFFTW3.

An issue arises only if you want to provide for use of libraries that are not in the linker's default search path, or where a different version of the library is found earlier in that path. That's the case for providing --with-foo options by which the builder can specify a location. But note that it's a somewhat special-case problem, at least when linking against dynamic libraries, because dev libraries are usually installed alongside runtime libraries, and if a dev lib is not found by the static linker at build time, then typically you need some kind of special provision for the runtime lib to be found by the dynamic linker at run time.

Nevertheless, if you want to check a list of possible library locations encoded into configure, then that can be done relatively easily. The generated configure is a shell script, and you can write literal code for it into your configure.ac without too much trouble. For example,

# Preserve the original value of LIBS
LIBS_save=$LIBS

# This is how we will report out the result
FFTW3_LIBS=

# Check the default locations first
AC_CHECK_LIB([fftw3], [fftw_plan_dft], [
  # libfftw3 found in the library search path
  FFTW3_LIBS=-lfftw3
], [
  # libfftw3 not found in the library search path; try some other paths
  # make the linker search the chosen path by adding an `-L` option to the LDFLAGS
  LDFLAGS_save=$LDFLAGS
  for fftw_libdir in
      /usr/lib/fftw
      /usr/lib/fftw3
      /usr/local/lib/fftw3
  do
    LDFLAGS="${LDFLAGS_save} -L${fftw_libdir}"
    AC_CHECK_LIB([fftw3], [fftw_plan_dft], [
      # library found
      FFTW3_LIBS="-L${fftw_libdir} -lfftw3"
      break
    ])
  done

  # restore the original LDFLAGS
  LDFLAGS=$LDFLAGS_save
])

# restore the original LIBS
LIBS=$LIBS_save

AS_IF([test x = "x${FFTW3_LIBS}"], [
  # configure fails if it does not find libfftw3
  AC_MSG_ERROR([libfftw3 not found])
])

# Make FFTW3_LIBS an output variable
AC_OUTPUT([FFTW3_LIBS])

Notable characteristics of that code include

  • saving and restoring variables used by configure in running tests (LDFLAGS) and reporting results (LIBS)
  • using a shell loop to test various options
  • using the on-success / on-error actions of AC_CHECK_LIB
    • understanding that AC_CHECK_LIB is a macro, not a function, so, for example, you can put a break into its parameters that will exit the loop in which AC_CHECK_LIB is used
  • using an output variable to report the result as a set of link options. You would use that in your Makefile.am by adding $(FFTW3_LIBS) to the appropriate *LIBADD or *LDADD variable(s). (Or if you're not using Automake, then by adding it to the link command in whatever manner is suitable.)

Of course, you can combine that with using a --with-foo option to support cases that you do not anticipate (left as an exercise).

1
votes

As fftw3 appears to install *.pc files, I would use the pkg-config based macros in configure.ac similar to

PKG_CHECK_MODULES([FFTW3], [fftw3])

or, if you want to be a little more helpful to people compiling your library, something like

PKG_CHECK_MODULES([FFTW3], [fftw3], [],
                  [AC_MSG_ERROR([fftw3 devel package not found])])

Of course, this will require pkg-config to be installed at autoreconf and configure time.

If someone happens to have fftw3 installed in an unusual place, they can add the installation directory of the *.pc files to the PKG_CONFIG_PATH environment variable.

In the Makefile.am file where define your libfoo library, you can then add lines like

libfoo_CFLAGS += $(FFTW3_CFLAGS)
libfoo_LIBADD += $(FFTW3_LIBS)

If you want to catch people early who attempt to run autoreconf on your source code without having pkg-config installed, you can add a line to configure.ac to make sure the PKG_CHECK_MODULES autoconf m4 macro is defined:

m4_pattern_forbid([PKG_CHECK_MODULES])dnl

This is rearely seen in the wild, though.

The advantage over the builtin AC_CHECK_LIB & Co macros is that the *.pc files may define more information. E.g.

[user@host ~]$ pkg-config --libs fftw3
-lfftw3 

contains no surprises but

[user@host ~]$ pkg-config --libs fftw3q
-lfftw3q -lquadmath 

may contain surprising additional flags. Distribution packages may also have added system specific information there.

IMHO, when a dependency ships *.pc files, using PKG_CHECK_MDOULE is very preferable to using AC_CHECK_LIB.