ldrg
ldrg

Reputation: 4501

GNU Autoconf C++ checks against C libraries

The project is written in C++ (AC_LANG([C++])) (autoconf 2.71) but is trying to find libz. The autoconf.ac to check for libz is like so:

AC_CHECK_HEADERS([zlib.h],
                 [AC_CHECK_LIB([z], [deflate, gzread, gzwrite, inflate], [],
                               [AC_MSG_ERROR([cannot find libz
                               ])])],
                 [AC_MSG_ERROR([cannot find libz headers
                 ])])

This results in autoconf test C++ code like so:

 namespace conftest {
   extern "C" int deflate, gzread, gzwrite, inflate ();
 }
 int
 main (void)
 {
 return conftest::deflate, gzread, gzwrite, inflate ();
   ;
   return 0;
 }

I'm using Apple's clang++ at version 12.0.0, and it fails to compile like so:

conftest.cpp:45:27: error: use of undeclared identifier 'gzread'; did you mean 'conftest::gzread'?
return conftest::deflate, gzread, gzwrite, inflate ();
                          ^~~~~~
                          conftest::gzread
conftest.cpp:40:27: note: 'conftest::gzread' declared here

I'm not a C++ master at all, but it looks like autoconf tried to shove all the symbols into a C++ namespace, but then didn't spell it out when referencing them later. How should the check be written and how do I get autoconf to emit it?

Upvotes: 1

Views: 130

Answers (1)

ndim
ndim

Reputation: 37797

The obvious solution to AC_CHECK_LIB only taking a single function name is to duplicate the AC_CHECK_LIB invocation for each function name:

AC_CHECK_HEADERS([zlib.h], [dnl action-if-found
  AC_CHECK_LIB([z], [deflate], [],
               [AC_MSG_ERROR([cannot find required libz function deflate()])])
  AC_CHECK_LIB([z], [inflate], [],
               [AC_MSG_ERROR([cannot find required libz function inflate()])])
  AC_CHECK_LIB([z], [gzread],  [],
               [AC_MSG_ERROR([cannot find required libz function gzread()])])
  AC_CHECK_LIB([z], [gzwrite], [],
               [AC_MSG_ERROR([cannot find required libz function gzwrite()])])
], [dnl action-if-not-found
  AC_MSG_ERROR([cannot find required libz.h])
])

However, code duplication is rarely good, so we can also use m4_foreach for that:

AC_CHECK_HEADERS([zlib.h], [dnl action-if-found
  m4_foreach([func], [[deflate], [inflate], [gzread], [gzwrite], [doesnotexist]], [dnl
    AC_CHECK_LIB([z], func, [], [dnl
      AC_MSG_ERROR([cannot find required libz function ][func][()])
    ])
    AC_MSG_CHECKING([LIBS])
    AC_MSG_RESULT(["${LIBS}"])
  ])
], [dnl action-if-not-found
  AC_MSG_ERROR([cannot find required libz.h])
])

This produces

checking for zlib.h... yes
checking for deflate in -lz... yes
checking LIBS... "-lz "
checking for inflate in -lz... yes
checking LIBS... "-lz -lz "
checking for gzread in -lz... yes
checking LIBS... "-lz -lz -lz "
checking for gzwrite in -lz... yes
checking LIBS... "-lz -lz -lz -lz "
checking for doesnotexist in -lz... no
configure: error: cannot find required libz function doesnotexist

The above is probably not very clean regarding m4 quoting and evaluating (see the unquoted func argument to AC_CHECK_LIB), but it appears to work. (This is a part of m4 I have not understood even after 20 years of hacking on autoconf+automake based build systems.)

That AC_CHECK_LIB adds -lz to LIBS several times should not make any builds fail. If you want to avoid that, you might need to replace AC_CHECK_LIB with an appropriate invocation of AC_TRY_LINK and handle adding -lz to the appropriate foo_LDADD separately.

Upvotes: 1

Related Questions