How to test a C++ library usability in configure.in?
Asked Answered
U

4

12

I'm working on a C++ project on GNU/Linux and I'm looking for a way to test the existence and usability of IBM Informix's library with the Autotools - namely, editing a configure.in. I don't have experience with Autotools, so basically I'm picking up from the project's configure.in et al. scripts and copying&changing where I feel needs to be changed. IOW, I've been adapting from the existing text in configure.in.

So far I've been using successfully the AC_CHECK_LIB in configure.in to test whether a certain library both exists and is usable. But this only seems to work with libraries with functions, not e.g. classes. Namely, this fails when testing Informix's libifc++.so library:

AC_CHECK_LIB(ifc++, ITString, 
        INFORMIX_LIB="-L$INFORMIX_LIB_LOCATION/c++ -lifc++ -L$INFORMIX_LIB_LOCATION -L$INFORMIX_LIB_LOCATION/dmi -L$INFORMIX_LIB_LOCATION/esql -lifdmi -lifsql -lifasf -lifgen -lifos -lifgls -lifglx $INFORMIX_LIB_LOCATION/esql/checkapi.o -lm -ldl -lcrypt -lnsl",
        echo "* WARNING: libifc++.so not found!"
        INFORMIX_INC=""
        INFORMIX_LIB=""
)

I've also tried using other combinations, like ITString::ITString, etc.

I haven't found a "pure" function in Informix's API (i.e., one that isn't contexted in a C++ class). So I'm hoping that either there's a way to use AC_CHECK_LIB in this context, or there's another autoconf/configure.in "command" for this specific use.

Thanks in advance for your feedback.

Uird answered 20/6, 2009 at 16:28 Comment(0)
C
6

There might be a cleaner way of achieving this, but I think your problem is that C++ methods get "mangled" to allow additional information about the method (argument & return types etc) to be encoded. For example; the method int A::foo(void) will get mangled to something like __ZN1A3fooEv.

So you need to find the mangled name of a method in the library. You can do this by using the nm command on Unix-like OSs:

$ nm libifc++.so | grep ITString

It's worth mentioning that the exact mangling format varies across different compilers; and so by embedding a certain compiler's mangled symbol in your configure.in it may not work on other platforms - YMMV.

Note: you can use the c++filt utility to demangle a name back to it's human-readable form; so for the example I gave previously:

$ c++filt __ZN1A3fooEv
A::foo()

See Name Mangling in C++ on Wikipedia for more information.

Callicrates answered 20/6, 2009 at 16:44 Comment(3)
Works-For-Me. I had thought about doing something like this, but it seemed like a hack. For example, I'm not sure what happens if the code is recompiled with a different Informix library version (I expect the mangled name to change). But hey, it works! :-)Uird
This should continue to work with a new library version (assuming the class and method names do not change), but may break if your compiler version changes, and will almost certainly break if someone else tries to compile your code on another compiler or compiler version.Germander
Too verbose, seriously, look up my answer on the bottom.Katlynkatmai
G
16

You've discovered a shortcoming of autotools, but one that can't really be helped. Autotools checks for symbol names in the library binary, and unlike C where symbol names of functions are identical to the function names, C++ "mangles" function's symbol names to accomplish things like function overloading. What's worse is that C++ doesn't really even have a "standard" mangling convention, so different C++ compilers may produce different symbol names for the same function. Thus, autotools can't check for C++ symbol names in a reliable manner.

Does the library you are trying to use have any functions that are declared with extern "C"? This causes the C++ compiler to generate standardized C-style symbol names, and autotools will be able to find them.

I ran into this issue trying to detect gtest and gmock (the Google unit testing and object mocking frameworks) with Autotools, and here's what I came up with:

# gtest has a main function in the gtest_main library with C linkage, we can test for that.
AC_CHECK_LIB([gtest_main], [main], [HAVE_GTEST=1] [TEST_LIBS="$TEST_LIBS -lgtest_main"], 
      AC_MSG_WARN([libgtest (Google C++ Unit Testing Framework) is not installed. Will not be able to make check.])) 

# gmock has no functions with C linkage, so this is a roundabout way of testing for it. We create a small test
# program that tries to instantiate one of gmock's objects, and try to link it with -lgmock and see if it works.
if test "$HAVE_GTEST"                                                                 
then                                                                                  
  saved_ldflags="${LDFLAGS}"                                                          
  LDFLAGS="${LDFLAGS} -lgtest -lgmock"                                                
  AC_LINK_IFELSE([AC_LANG_PROGRAM([#include <gmock/gmock.h>], [testing::Cardinality dummy])],
    [TEST_LIBS="$TEST_LIBS -lgmock"] [HAVE_GMOCK=1],                                           
    [AC_MSG_WARN([libgmock (Google C++ Object Mocking Framework) is not installed. Will not be able to make check.])])
  LDFLAGS="${saved_ldflags}"                                                                                          
fi          
Germander answered 20/6, 2009 at 16:48 Comment(0)
C
6

There might be a cleaner way of achieving this, but I think your problem is that C++ methods get "mangled" to allow additional information about the method (argument & return types etc) to be encoded. For example; the method int A::foo(void) will get mangled to something like __ZN1A3fooEv.

So you need to find the mangled name of a method in the library. You can do this by using the nm command on Unix-like OSs:

$ nm libifc++.so | grep ITString

It's worth mentioning that the exact mangling format varies across different compilers; and so by embedding a certain compiler's mangled symbol in your configure.in it may not work on other platforms - YMMV.

Note: you can use the c++filt utility to demangle a name back to it's human-readable form; so for the example I gave previously:

$ c++filt __ZN1A3fooEv
A::foo()

See Name Mangling in C++ on Wikipedia for more information.

Callicrates answered 20/6, 2009 at 16:44 Comment(3)
Works-For-Me. I had thought about doing something like this, but it seemed like a hack. For example, I'm not sure what happens if the code is recompiled with a different Informix library version (I expect the mangled name to change). But hey, it works! :-)Uird
This should continue to work with a new library version (assuming the class and method names do not change), but may break if your compiler version changes, and will almost certainly break if someone else tries to compile your code on another compiler or compiler version.Germander
Too verbose, seriously, look up my answer on the bottom.Katlynkatmai
C
3

If the library you are checking for supports pkg-config, this becomes very easy. Here is all I added to my configure.in to check for and enable gtest and gmock:

dnl ************************************
dnl Check for googletest and googlemock
dnl ************************************

PKG_CHECK_MODULES(gtestmock, libgtest >= 0.4.0, libgmock >= 0.4.0)
AC_SUBST(gtestmock_LIBS)
AC_SUBST(gtestmock_CFLAGS)

And then in my Makefile.am somewhere:

sometarget_CXXFLAGS = $(gtestmock_CFLAGS) $(AM_CXXFLAGS)
sometarget_LDADD    = $(gtestmock_LIBS)

Pretty trivial, eh?

Chyme answered 24/3, 2010 at 8:31 Comment(1)
There are problems with using pkg-config, though. And, more fundamentally, pkg-config and the autotools work in a different way. Autoconf checks for features, whereas pkg-config tests for package versions. If you're trying to do things the autotools way, which should give you maximum compatibility across systems, I wouldn't suggest using pkg-config at all.Uptrend
K
0
AC_LANG_CPLUSPLUS
AC_CHECK_LIB(Sockets, main)

Caveat: http://lists.gnu.org/archive/html/autoconf/2006-09/msg00019.html

Katlynkatmai answered 2/8, 2012 at 13:28 Comment(4)
A bit more explanation would help. Your sample requires that exactly main is specified and only checks for existance of the library. But the generated program has UB because in C++ main is not allowed to call main. Which BTW is mentioned in the link that you provide.Kirtle
Maybe because the link was given as a caveat? Hm?Katlynkatmai
So why not change to AC_LANG_C where main is allowed to call main? And as said already: you are just giving some code without any explanation, but an explanation would really help.Kirtle
So why not edit my answer to make it more informative instead of bickering? Goodbye.Katlynkatmai

© 2022 - 2024 — McMap. All rights reserved.