views:

171

answers:

3

What is the best way to auto detect library dependencies in a C/C++ project?

I have a project where I have all the dependencies on the machine. It builds and runs. Now I want to put together a autotools build system. I am looking for a good way to auto detect all the dependencies needed such as header files used and libraries needed for linking.

The library bit seems to be the hardest for me to figure out. I'd like to be able to say, generate AC_CHECK_LIB commands for every function in a list or something. I could probably do this in Perl, but I've got to imagine it already exists elsewhere.

What I know is that I can view symbols with objdump and nm, I can find what library a function belongs to with these utilties, then I can manually enter an AC_CHECK_LIB command in my configure.ac to check for it. Automation would be awesome at this point.

Thanks, Chenz

A: 

On Windows I've used Dependency Walker for stuff like that. Its output is verbose, but it will generally show you every library that is required by the executable.

I don't know of anything like that for linux or mac, but I'm sure something has to exist.

Herms
A: 

That sort of exhaustive testing (i.e., every function) is unnecessary. Not to mention that it would be hard to maintain and take a while to run.

Test for features that you know warrant a test. If you're just testing for the existence of a library, pick a commonly used function to use in your test. If you want to make sure some feature only in newer vesions is available, test using a function only found in those newer versions.

Braden
A: 

I had a similar challenge now. autoconf is really not so handy for C++ tricks, but it has basic bricks to build the functionality on the top. My suggestions after looking here and there:

  • Read this article, it will bring you fresh ideas
  • Look at the sources for autoconf macros at ac-archive (it is included into Debian, so you can use it as is)
  • I personally have written simple helper, which is copied from AC_CHECK_LIB and AX_CXX_CHECK_LIB. Yes, you need to write a mini-test-program, but this allows you to test types, classes (sizeof might work, but what about constructors?), inline functions (this you can't do with help of linker) and external functions (you can't do it with nm).

From aclocal.m4:

# SYNOPSIS
#
# AX_TRY_LINK(library, includes, function-body [, action-if-true [, action-if-false]])
#
# DESCRIPTION
#
# This function is a wrapper around AC_ARG_WITH, which adds -I"value" to CPPFLAGS.
# "--with-" variable is initialized to default value, if it is passed.
#
AC_DEFUN([AX_TRY_LINK], [
    dnl Below logic is a workaround for the limitation, that variables may not allow
    dnl symbols like "+" or "-". See AC_CHECK_LIB source comments for more information.
    m4_ifval([$4], , [AH_CHECK_LIB([$1])])
    AS_LITERAL_IF([$1],
        [AS_VAR_PUSHDEF([ac_Lib], [ac_cv_lib_$1_$2])],
        [AS_VAR_PUSHDEF([ac_Lib], [ac_cv_lib_$1''_$2])])

    AC_CACHE_CHECK([for -l$1], [ac_Lib], [
        dnl Save the current state
        AC_LANG_SAVE
        AC_LANG_CPLUSPLUS
        ax_try_link_save_LIBS=$LIBS
        LIBS="-l$1 $LIBS"

        AC_TRY_LINK([$2], [$3], [AS_VAR_SET([ac_Lib], [yes])], [AS_VAR_SET([ac_Lib], [no])])

        dnl Restore the state to original regardless to the result
        LIBS=$ax_try_link_save_LIBS
        AC_LANG_RESTORE
    ])

    dnl If the variable is set, we define a constant and push library to LIBS by default or execute $4, otherwise execute $5.
    AS_VAR_IF([ac_Lib], [yes],
        [m4_default([$4], [
            AC_DEFINE_UNQUOTED(AS_TR_CPP(HAVE_LIB$1))
            dnl Do not prepend a library, if it is already in the list:
            (echo $LIBS | grep -q -- "-l$1 ") || LIBS="-l$1 $LIBS"
        ])],
        [$5]
    )
    AS_VAR_POPDEF([ac_Lib])
]) # AX_ARG_WITH

Now in configure.ac:

AC_INIT([ABC], [1.2.3])
AC_LANG([C++])
AC_PROG_CXX
AC_CXX_HAVE_STL

if test "x${ac_cv_cxx_have_stl}" != "xyes"; then
    AC_MSG_ERROR([STL was not found; make sure you have installed libstdc++-dev])
fi

...

dnl openbabel library

sr_openbabel_lib=yes

AC_CHECK_HEADERS([openbabel/mol.h openbabel/obconversion.h openbabel/builder.h], [], [sr_openbabel_lib=no])
AX_TRY_LINK([openbabel], [
    #include <openbabel/mol.h>
    #include <openbabel/obconversion.h>
    #include <openbabel/builder.h>
], [
    OpenBabel::OBAtom atom;
    OpenBabel::OBMol mol;
    OpenBabel::OBConversion conversion;

    atom.IsHeteroatom();
    atom.IsCarbon();

    mol.NumAtoms();
    mol.NumBonds();
    mol.NumRotors();
    mol.GetAtom(0);

    conversion.ReadString(&mol, "");
    conversion.WriteString(&mol, false);
], [], [sr_openbabel_lib=no])

if test ${sr_openbabel_lib} != yes; then
    AC_MSG_ERROR([openbabel headers or library was not found (use --with-openbabel to define custom header location)])
fi
dma_k