views:

392

answers:

3

Hi,

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:

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.

+4  A: 

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 ibifc++.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.

Dave Rigby
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! :-)
jbatista
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.
Tyler McHenry
@Tyler - a valid point; I've highlighted this in the answer.
Dave Rigby
+6  A: 

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
Tyler McHenry
A: 

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?

jmglov