CAB
CAB

Reputation: 1045

libtool doesn't provide library dependencies to link

I am using libtool 2.2.6b on ubuntu lucid, and libtool 2.4.2 on ubuntu precise. On lucid my project will link properly. On precise it fails to link. Here's example code that demonstrates my problem;

configure.ac

AC_INIT([ltp], [0.0.1], [someone])
AM_INIT_AUTOMAKE
AC_CONFIG_HEADERS([config.h])
AC_CONFIG_MACRO_DIR([.m4])
AC_CONFIG_FILES([Makefile foo/Makefile bar/Makefile wah/Makefile])
AC_PROG_CXX
AC_PROG_LIBTOOL
AM_SANITY_CHECK
AC_LANG_CPLUSPLUS
AC_OUTPUT

Makefile.am

SUBDIRS = foo bar wah
ACLOCAL_AMFLAGS = -I .m4

foo/Foo.h

#ifndef FOO_FOO_H_
#define FOO_FOO_H_
namespace Foo
{
  class Foo
  {
  public:
    Foo(long l);
  private:
    long l;
  };
}
#endif

foo/Foo.cpp

#include "foo/Foo.h"
namespace Foo
{
  Foo::Foo(long l) : l(l) {}
}

foo/Makefile.am

lib_LTLIBRARIES = libfoo.la
libfoo_la_SOURCES = Foo.cpp
libfoo_la_CPPFLAGS =
libfoo_la_LDFLAGS = -release 0.0.1
libfoo_la_LIBADD =

bar/Bar.h

#ifndef BAR_BAR_H_
#define BAR_BAR_H_
#include "foo/Foo.h"
namespace Bar
{
  class Bar
  {
  public:
    Bar(const Foo::Foo & f);
  private:
    Foo::Foo f;
  };
}
#endif

bar/Bar.cpp

#include "bar/Bar.h"
namespace Bar
{
  Bar::Bar(const Foo::Foo & f) : f(f) { }
}

bar/Makefile.am

lib_LTLIBRARIES = libbar.la
libbar_la_SOURCES = Bar.cpp
libbar_la_CPPFLAGS =
libbar_la_LDFLAGS = -release 0.0.1
libbar_la_LIBADD = -L../foo -lfoo

wah/main.cpp

#include "bar/Bar.h"
int main(int argc, char * argv[])
{
  Bar::Bar( 5 );
  return 0;
}

wah/Makefile.am

bin_PROGRAMS = wah
wah_SOURCES = main.cpp
wah_CPPFLAGS =
wah_LDADD = -L../bar -lbar

On Lucid, wah links, on Precise, it fails with:

wah/main.cpp:5 undefined reference to `Foo::Foo::Foo(long)'

I can fix this by adding -L../foo -lfoo to wah_LDADD, but really, isn't libtool supposed to do that for me automagically? The libtool manual section on `Linking executables' seems to indicate that is exactly what it should do.

Upvotes: 5

Views: 3923

Answers (3)

Rufflewind
Rufflewind

Reputation: 8956

I suppose you could say it's more of a difference in philosophy. The point of Debian's change is to encourage users to be explicit about what they depend on, which reduces the amount of unnecessary churn when dependencies deep down the tree get upgraded.

When link_all_deplibs=yes (unmodified libtool), if your program wah depends on bar and bar depends on foo, then it is implied that wah depends foo as well.

When link_all_deplibs=no (Debian's modified libtool), if your program wah depends on bar and bar depends on foo, then it is not implied that wah depends foo as well.

So, taking Debian's perspective, this is false in your program: wah does depend on foo by virtue of this line:

  Bar::Bar( 5 );

Here, you are calling the constructor of Foo::Foo implicitly. As far as the C++ compiler is concerned, your program is really more like:

  Bar::Bar( Foo::Foo( 5 ) );

Therefore, wah depends on foo not just indirectly, but directly. Hence, from Debian's perspective, you are should explicitly link to foo via -lfoo.

In particular, this is not the same situation as libtool's example for Linking Executables. In that example, main.o does not explicitly depend on libm, thus -lm should, in principle, be unnecessary when linking the main.o (main.c does not call cos directly). Perhaps the reason why libtool links recursively is as a work around for older systems where linkers are unable to handle indirect dependencies?

Upvotes: 2

ldav1s
ldav1s

Reputation: 16305

Works for me on Ubuntu 12.04 (Precise Pangolin) 32-bit, libtool 2.4.2.

I did have to change your Makefiles a bit to make dist (more) correctly:

foo/Makefile.am:

lib_LTLIBRARIES = libfoo.la
libfoo_la_SOURCES = Foo.cpp Foo.h
libfoo_la_CPPFLAGS =
libfoo_la_LDFLAGS = -release 0.0.1
libfoo_la_LIBADD =

bar/Makefile.am:

lib_LTLIBRARIES = libbar.la
libbar_la_SOURCES = Bar.cpp Bar.h
libbar_la_CPPFLAGS =
libbar_la_LDFLAGS = -release 0.0.1
libbar_la_LIBADD = -L../foo -lfoo

wah/Makefile.am

bin_PROGRAMS = wah
wah_SOURCES = main.cpp ../bar/Bar.h
wah_CPPFLAGS =
wah_LDADD = -L../bar -lbar

Here's how it links main.cpp:

make[2]: Entering directory `/xxx/ltp-0.0.1/wah'
g++ -DHAVE_CONFIG_H -I. -I..     -g -O2 -MT wah-main.o -MD -MP -MF .deps/wah-main.Tpo -c -o wah-main.o `test -f 'main.cpp' || echo './'`main.cpp
mv -f .deps/wah-main.Tpo .deps/wah-main.Po
/bin/bash ../libtool --tag=CXX   --mode=link g++  -g -O2   -o wah wah-main.o -L../bar -lbar 
libtool: link: g++ -g -O2 -o .libs/wah wah-main.o  -L../bar /xxx/ltp-0.0.1/bar/.libs/libbar.so -L../foo /xxx/ltp-0.0.1/foo/.libs/libfoo.so

isn't libtool supposed to do that for me automagically?

Yes, it does, at least when the distribution tarball is created on a non-Ubuntu distribution. After I autoreconf on an Ubuntu box, I get the same error you do. Apparently (according to adl) the Ubuntu distro has a patched version of libtool which sets the libtool script variable:

link_all_deplibs=no

I patched the configure generated libtool script to replace all these instances with:

link_all_deplibs=unknown

and everything linked as expected. I suppose you could do the same in a script that invokes autoreconf. Or install a non-patched version of libtool on the Ubuntu host. Or patch the patched libtool on the Ubuntu host. So there's a few options on how to fix it.

Upvotes: 1

adl
adl

Reputation: 16034

On any Debian machine I use for development, I have to compile and install Libtool by hand, because the Debian-supplied version is patched and ignores dependencies in a way that break my builds.

If Ubuntu's version is similar, you might want to install Libtool from source too.

Upvotes: 5

Related Questions